testing of javacript

44
Testing Javascript Lei Kang @ Kiwiplan

Upload: lei-kang

Post on 11-May-2015

4.305 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Testing of javacript

Testing Javascript

Lei Kang @ Kiwiplan

Page 2: Testing of javacript

Do you want...

Unit Testing of JavaScript code?

Continuous Integration?

Automated Testing for JavaScript intensive Web App?

Page 3: Testing of javacript

Are those your itches for Web Development?

Every good work of software starts by scratching a developer’s personal itch.

-- The Cathedral and the Bazaarby Eric S. Raymond

Page 4: Testing of javacript

My itches of JavaScript

Object Oriented Javascript

Javascript with Ruby’s flavor

Distributed Event Registering and Triggering

Reflection of Javascript

Unit Testing

Continuous Integration for Javascript Project

Automated Web UI testing

Page 5: Testing of javacript

Today’s Story

Unit Testing using Rhino and RhinoUnit

Continuous Integration using Jenkins(Hudson)

Automated Web UI testing using iMacros

Page 6: Testing of javacript

Rhino?

Page 7: Testing of javacript

Rhino isAn open-source implementation of JavaScript written entirely in Java. It is typically embedded into Java applications to provide scripting to end users.

http://www.mozilla.org/rhino/

Page 8: Testing of javacript

Rhino now

The Mozilla Rhino engine for the JavaScript programming language, is currently included as a feature in the JDK 6 and JRE 6 libraries.

Page 9: Testing of javacript

Rhino can

Run JavaScript inside Java

ScriptEngineManager mgr = new ScriptEngineManager(); ScriptEngine jsEngine = mgr.getEngineByName("JavaScript"); try { jsEngine.eval("print('Hello, world!')"); } catch (ScriptException ex) { ex.printStackTrace(); }

Page 10: Testing of javacript

Rhino can

Run Java inside JavaScript

importPackage(javax.swing); var optionPane = JOptionPane.showMessageDialog(null, 'Hello, world!');

Page 11: Testing of javacript

Rhino can Run in the Terminal: Linux, Windows and MacOS X: jrunscript

$ sudo apt-get install rhino; js

Page 12: Testing of javacript

already feeling impatient?

Here comes RhinoUnit

An Ant based Javascript testing framework

RhinoUnit is run from an ANT scriptdef task using the Rhino engine - and uses all the helpful things that ANT provides for that.

Page 13: Testing of javacript

What RhinoUnit can doAlmost the same APIs with JUnit

• string and object comparisons

• regexp comparisons

• collection comparisons (contains, containsExactly, etc)

• ensure that a function has been called (by wrapping it with assert.mustCall(), or using an assert.functionThatMustBeCalled()).

• ensure that an exception is thrown (using shouldThrowException(...)

• ensure that the global namespace isn't polluted by poor variable scoping. (I will talk about it later)

Page 14: Testing of javacript

A general example

/** * Number.times function. 3.times(function(item){...}) * * @param handler function * @returns {Array} */Number.prototype.times = function(handler) {

var results = new Array();if (this > 0 && this == parseInt(this)) {

for ( var i = 0; i < Math.ceil(this); i++) {results.push(handler(i));

}} else {

throw "Illegal number for times() function. Positive integer is required.";}return results;

};

we have a simple function like this

Page 15: Testing of javacript

A general example

eval(loadFile("src/com/ciphor/ruby/Number.js"));var testNumber;

testCases(test,

function setUp(){testNumber = 12;

},

function testNumberTimes(){var aNumber = new Number(10);var temp = 0;var result = aNumber.times(function(item){

temp++;return aNumber*item;

});assert.that(temp, eq(10));assert.that(result, isCollectionContainingOnly(0,10,20,30,40,50,60,70,80,90));

});

Test code goes like this

Page 16: Testing of javacript

Our Ant build.xml<project name="CiphorJS" basedir="." default="run-unit-tests">

<scriptdef name="rhinounit" src="lib/rhinounit/src/rhinoUnitAnt.js" language="javascript">

<attribute name="options"/><attribute name="ignoredglobalvars"/><attribute name="haltOnFirstFailure"/><attribute name="rhinoUnitUtilPath"/><element name="fileset" type="fileset"/>

</scriptdef>

<target name="run-unit-tests"><rhinounit options="{verbose:true, stackTrace:true}"

haltOnFirstFailure="false" rhinoUnitUtilPath="lib/rhinounit/src/rhinoUnitUtil.js">

<fileset dir="test"><include name="Test*.js"/>

</fileset></rhinounit>

</target></project>

I am sure you know how to do the next

Page 17: Testing of javacript

familiar with this?

run-unit-tests:[rhinounit] Testsuite: TestCore.js[rhinounit] *** Empty TestCase, unavailable for OOAD module. ***[rhinounit] Tests run: 1, Failures: 0, Errors: 0[rhinounit] Testsuite: TestEve.js[rhinounit] Tests run: 4, Failures: 0, Errors: 0[rhinounit] Testsuite: TestReflection.js[rhinounit] Tests run: 5, Failures: 0, Errors: 0[rhinounit] Testsuite: TestRubyArray.js[rhinounit] Tests run: 26, Failures: 0, Errors: 0[rhinounit] Testsuite: TestRubyNumber.js[rhinounit] Tests run: 3, Failures: 0, Errors: 0[rhinounit] Testsuite: TestRubyOO.js[rhinounit] Tests run: 7, Failures: 0, Errors: 0[rhinounit] Testsuite: TestRubyString.js[rhinounit] Tests run: 12, Failures: 0, Errors: 0BUILD SUCCESSFULTotal time: 922 milliseconds

Page 18: Testing of javacript

want to see more?

assert.that(actual, predicate)assert.mustCall(onThisObject, thisMethod)assert.mustCallNTimes(onThisObject, numberOfTimes, thisMethod)assert.functionThatMustBeCalled(thisMethod, originalFunction)assert.functionThatMustBeCalledNTimes(thisMethod, numberOfTimes, originalFunction)assert.mustNotCall(onThisObject, thisMethod)assert.functionThatMustNotBeCalled(thisMethod)assert.fail(message)assert.callStack(optionalIgnoreAfterMatching)

eq(expected)similar(expected)matches(regExp)isTrue(message)isFalse(message)not(predicate)hasConstructor(expected)isA(expected)isOfType(expected)isCollectionContaining(value, value, value...)isCollectionContainingOnly(value, value, value...)containsInOrder(value, value, value...)isNull(message)eqFloat(expected, accuracy)shouldThrowException(theTest, message, checkException)

Assert Object

Test Functions

http://code.google.com/p/rhinounit/

Test Functions

Page 19: Testing of javacript

Continuous Integration

Why do we need CI?

Can we use CI for Javascript Project?

Which CI system are we going to use?

How to do it?

Page 20: Testing of javacript

Jenkins

jenkins-ci.org

JenkinsJenkins

Page 21: Testing of javacript

Jenkins

Formerly known as Hudson

Free to use (applause!)

Written in Java

Distributed by jenkins.war (Easy to deploy)

Native package for ubuntu

Page 22: Testing of javacript

How I use it

A Javascript Project in Eclipse

Using git for version controlling, you need a git plugin for eclipse

Source code hosted on GitHub (github.com)

Unit tested by RhinoUnit (Ant)

Interested in Git?

Page 23: Testing of javacript

Let Jenkins working with githubInstall Github plugin

Install Git plugin

Page 24: Testing of javacript

Let Jenkins working with github

Create a new job for your project

Page 25: Testing of javacript

Let Jenkins working with github

Set Ant Target to run

Page 26: Testing of javacript

Let Jenkins working with github

Set Git Publisher

Optionally push merge results, tags, and/or branches to remote repositories.

Page 27: Testing of javacript

Let Jenkins working with github

Generate SSH key and add it to GitHub

Set Git autentication info in Jenkins workspace

$ git config user.name “your.name”$ git config user.email “[email protected]

Page 28: Testing of javacript

Hooray!

Page 29: Testing of javacript

10:24:59 Started by user anonymous10:24:59 Checkout:workspace / /var/lib/jenkins/jobs/CiphorJS/workspace - hudson.remoting.LocalChannel@1077aa710:24:59 Using strategy: Default10:24:59 Last Built Revision: Revision 711a1c557c248b5e45364d3aafd8a4c98031f8a1 (local/master)10:24:59 Checkout:workspace / /var/lib/jenkins/jobs/CiphorJS/workspace - hudson.remoting.LocalChannel@1077aa710:24:59 GitAPI created10:24:59 Fetching changes from the remote Git repository10:24:59 Fetching upstream changes from /home/lei.kang/workspaces/java/CiphorJS/.git10:24:59 [workspace] $ git fetch -t /home/lei.kang/workspaces/java/CiphorJS/.git +refs/heads/*:refs/remotes/local/*10:25:00 [workspace] $ git ls-tree HEAD10:25:00 Fetching upstream changes from [email protected]:kangleay/CiphorJS.git10:25:00 [workspace] $ git fetch -t [email protected]:kangleay/CiphorJS.git +refs/heads/*:refs/remotes/origin/*10:25:13 [workspace] $ git ls-tree HEAD10:25:13 Seen branch in repository local/master10:25:13 Seen branch in repository origin/master10:25:13 Commencing build of Revision 711a1c557c248b5e45364d3aafd8a4c98031f8a1 (local/master)10:25:13 GitAPI created10:25:13 Checking out Revision 711a1c557c248b5e45364d3aafd8a4c98031f8a1 (local/master)10:25:13 [workspace] $ git checkout -f 711a1c557c248b5e45364d3aafd8a4c98031f8a110:25:13 [workspace] $ git tag -a -f -m "Hudson Build #37" hudson-CiphorJS-3710:25:13 Recording changes in branch local/master10:25:14 [workspace] $ git whatchanged --no-abbrev -M –pretty=raw 711a1c557c248b5e45364d3aafd8a4c98031f8a1..711a1c557c248b5e45364d3aafd8a4c98031f8a1

What is it doing behind?

Page 30: Testing of javacript

What is it doing behind?10:25:14 [workspace] $ ant -file build.xml run-unit-tests10:25:14 Buildfile: build.xml10:25:15 10:25:15 run-unit-tests:10:25:15 [rhinounit] Testsuite: TestCore.js10:25:15 [rhinounit] *** Empty TestCase, unavailable for OOAD module. ***10:25:15 [rhinounit] Tests run: 1, Failures: 0, Errors: 010:25:15 [rhinounit] 10:25:15 [rhinounit] Testsuite: TestEve.js10:25:15 [rhinounit] Tests run: 4, Failures: 0, Errors: 010:25:15 [rhinounit] 10:25:15 [rhinounit] Testsuite: TestReflection.js10:25:15 [rhinounit] Tests run: 5, Failures: 0, Errors: 010:25:15 [rhinounit] 10:25:15 [rhinounit] Testsuite: TestRubyArray.js10:25:15 [rhinounit] Tests run: 26, Failures: 0, Errors: 010:25:15 [rhinounit] 10:25:15 [rhinounit] Testsuite: TestRubyNumber.js10:25:15 [rhinounit] Tests run: 3, Failures: 0, Errors: 010:25:15 [rhinounit] 10:25:15 [rhinounit] Testsuite: TestRubyOO.js10:25:15 [rhinounit] Tests run: 7, Failures: 0, Errors: 010:25:15 [rhinounit] 10:25:15 [rhinounit] Testsuite: TestRubyString.js10:25:15 [rhinounit] Tests run: 12, Failures: 0, Errors: 010:25:15 [rhinounit] 10:25:15 10:25:15 BUILD SUCCESSFUL10:25:15 Total time: 0 seconds10:25:15 GitAPI created10:25:15 [workspace] $ git tag -d hudson-CiphorJS-3710:25:15 [workspace] $ git tag -a -f -m "Hudson Build #37" hudson-CiphorJS-37-SUCCESS10:25:15 GitAPI created10:25:15 Pushing HEAD to branch master at repo origin10:25:15 [workspace] $ git push [email protected]:kangleay/CiphorJS.git HEAD:master

10:25:20 Finished: SUCCESS

Page 31: Testing of javacript

What have I done?

Commit Git Local Repository Detected by

Build and TestJenkins

workspace

Git Remote Repository(GitHub)

PublishSuccess

As an open source project, people now can check out source from github and enjoy!

Page 32: Testing of javacript

Extremely bored?Should I continue?

Page 33: Testing of javacript

Automated Web UI Testing

A lot of options

Selenium, Tellurium...

For simplicity, iMacros

Page 34: Testing of javacript

iMacros

Just DRYDon't Repeat Yourself

Page 35: Testing of javacript

iMacros

Works for both IE and Firefox

Page 36: Testing of javacript

iMacros

Let's do itActions speak louder than words.

Page 37: Testing of javacript

Web Testing

Page 38: Testing of javacript

Web Testing

Page 39: Testing of javacript

Web Testing

Page 40: Testing of javacript

Web Testing

Page 41: Testing of javacript

Web Testing

Page 42: Testing of javacript

OK, That's the whole story today, Thank you!

Page 43: Testing of javacript

Reference

Rhino http://www.mozilla.org/rhino/

RhinoUnit http://code.google.com/p/rhinounit/

Jenkins http://jenkins-ci.org/

iMacros https://addons.mozilla.org/en-us/firefox/addon/imacros-for-firefox/

CiphorJS http://www.ciphor.com/wiki/index.php/CiphorJS

Page 44: Testing of javacript

Coming soon...

Javascript with Ruby flavor

• Ruby Array object

• Ruby Number object

• Ruby String object

• ...

Reflection of Javascript

Event Listening Extension

CiphorJS project

Object oriented way of writing javascript

• Inheritance

• Package importing

• Interface

• ...