Friday, July 06, 2007

Creating a GwtTestCase under eclipse

Creating a new JUnit test case with GWT integration - and having it work with Eclipse.

Perhaps you have a project structure that's different than what the GWT tools provide for you automatically? Perhaps you like to know what's going on under the hood? Either way, these steps should illuminate a little bit about how GWT wants you to invoke its GWTTestCase tests.

Steps:
- Create a test folder, and mirror the "client" package name you have under src. Eg: src/com/goodstuff/client/ would have an associated test/com/goodstuff/client/ directory for tests. The tests will not run successfully if you use a different package name.

- Create a test case within this package. Have it extend from the com.google.gwt.junit.client.GWTTestCase class.

- Implement the getModuleName() method. More than likely this will be the same for all your tests. This will be the Module Name of your main application. For me, it was "davefoolery.gwtTest.TestTwoApp". A 'module' has a corresponding file ending in .gwt.xml, so you'll know you have the right module name if the module com.yourcompany.FancyApp has an associated com/yourcompany/FancyApp.gwt.xml file.

- Create a run configuration for this test - easiest way to do that is to go run->run as JUnit Test. This will fail horribly, don't worry - we're not done yet.

- Add the gwt-dev-*.jar to the classpath of the run configuration for this test. If you want (not recommended), you could also add it to the project wide configuration. * See note at end.

- Ensure both "src" and "test" sub directories are in the classpath configuration for this test - GWT needs these to find the various files we're pointing at (test .java files, etc).

- Ensure you don't use any Java 5 features in your GWTTestCase tests.

- Run your test - it should pass now.


*NOTE: The -dev*.jar files use different names under Linux/OSX/Windows, and so will cause your runtime configurations/project files to be unportable if a different platform author needs to import your .project/.classpath/... settings.

Thursday, March 09, 2006

Cruise Control and X10 devices - the fiddly bits

Cruise control integrates nicely with X10 - which is great if you want to light up a lavalamp (or a life sized dancing pirate) to indicate build results.

So, you'd probably want to add a line like this to your Cruise Control config file.



You'd want two for the red/green combination, passing onWhenBroken="false" to the green one and using a different device code.

The main thing to note is that the java comm library is braindead with regards to
finding the javax.comm.properties file. If you can, install Cruise Control to a
directory without any spaces. If not, follow below.

Installed Without Spaces (in windows):

The current (2.4.1) build of Cruise Control doesn't supply win32com.dll or the javax.comm.properties files, but does supply comm.jar and x10.jar. Get these from: here (Update: sun no longer distributes to windows version, GO SUN!) . Put javax.comm.properties and win32com.dll in the same directory as the comm.jar file.

Installed With Spaces
(in windows):

Follow the instructions above.

The comm jar does some lame classpath parsing to find the javax.comm.properties
file. This means that you must:

- Have the comm.jar outside of any implicitly defined library directory -
so you need to have it in the classpath somehow.

- The directory this file lives in must not have a space.

- The javax.comm.properties files must live in exactly the same place as the jar file.

So the easiest way is to:

make a c:\javacomm directory
put comm.jar and javax.comm.properties in c:\javacomm
add c:\javacomm\comm.jar to the start of the cruise control classpath

Why didn't they just do getResource("javax.comm.properties")?? I dunno.


Other notes:

- set the CCDIR environment variable to where you installed cruise control - but append \main underneath it.

so C:\Program Files\CruiseControl-x.y.x\main

Also see the note on http://cruisecontrol.sourceforge.net/main/configxml.html about copying
win32com.dll if you need to.

Hopefully that will fill in the missing bits that I've not seen anyone mention before.

Wednesday, March 01, 2006

Unit Testing JavaScript from within Java

(Reposted for the benefit of the Agile Planetters)

So you're developing a web app. You're probably using Java. You might even be using some of that super cool AJAX. But with all that logic on the client side, you better be sure you're testing it.

You could use JsUnit - that's an excellent solution, as it can be run from multiple real browsers ensuring the code works the way it should with that particular javascript implementation. Unfortunately, we don't want to have to do separate tests - unit testing with JUnit, and javascript unit testing with a browser. Since these are true unit tests of javascript code, it would be nice to integrate it into our JUnit testing cycles. Another benefit of testing javascript from within java is that we can use dynamically generated mocks to provide simulated collaborators - just like standard java tests can.

An alternative to using JsUnit and a browser, is to use Mozilla Rhino (http://www.mozilla.org/rhino/) to interpret the javascript from within Java. This should give you good confidence that the logic is implemented correctly. This allows for rapid feedback during your TDD sessions. No browser windows to pop up, nothing fancy to set up on the continuous integration side, and it's cross platform. And best of all, we can mock out any objects the script expects. Note that you should test your logic code here, I would recommend to keep the browser-specific code (stuff manipulating truly browser specific objects) tested in JsUnit.

Note that this route doesn't provide you with the standard objects that a browser would normally provide - no access to the document, etc. It would just be used for "logic" routines. I suggest having a split between logic routines, and ones which interact with the browser - and use JsUnit or WATIR/Selenium/PAMIE to test that the browser routines work properly.

For my javascript JUnit test, I've done the following:

protected void setUp() throws Exception {
super.setUp();
ctx = Context.enter();
scope = ctx.initStandardObjects(null);
}


protected void tearDown() throws Exception {
try
{
Context.exit();
}
finally
{
super.tearDown();
}
}


This ensures that the (thread local) javascript context is initialized/cleaned up properly.

You then wish to import the script under test into the context:

ctx.evaluateReader(scope, getReaderForResource("TestJavaScript.js"), "TestJavaScript.js", 0, null);

Get the Function placeholder for the function we will call:

Object functionRtnObj = scope.get("anyFunction", scope);
assertTrue(functionRtnObj instanceof Function);
Function functionObj = (Function) functionRtnObj;

Make the actual call with supplied parameters:

Object result = functionObj.call(ctx, scope, scope, new Integer[] {new Integer(1)});

Do some assertions on the return value:

assertNotNull(result);
assertEquals("anyReturnValue", result);

That's it!

NOTE: we cannot create javascript unit tests using JsUnit and run them from within java by using Rhino because it depends on various browser specific objects. An option (which I haven't verified yet) might be to write your tests in JsUnit, and use HtmlUnit (which uses Rhino for javascript) to simulate a browser. This way we can run the tests through a quick java system (suitable for a continuous integration system), and through various real browsers. All (or most - HtmlUnit is by no means complete) of the normal browser objects should be available. No mocks though :)

Enjoy!

Monday, January 16, 2006

Browser based testing with Watir - integrating into cruise control

[Update: Check out This Blog for an excellent way to get junit xml style output from ruby Test::Unit]

WATIR (www.watir.org) is a great functional testing tool that drives IE with Ruby. (It has plans to support Firefox and Safari too).

Since it's driven through the DOM of IE, it can drive the browser just as a normal user would, and do assertions on things like AJAX functionality. This also results in far less fragility than with a record/playback solution.

It's also driven through Test::Unit - Ruby's xUnit testing framework. This is good because you can integrate it into Cruise Control.

Justa couple notes on how to get this going:
1) Don't use the ServiceWrapper - just have a CI specific account login automatically, and have a startup script load cruise control. There are access control issues when running IE from the service account (especially if no one is currently logged into the local machine).

2) Route the output of your xUnit tests to a junit xml style file. Following something like http://meb.home.cern.ch/meb/xPyUnit.htm is a good way. Our solution was to create a different TestRunner, and override the finished() method. It's kind of hacky, so not worth publicizing :)

3) Return a non-zero error code from ruby if the tests fail, and set failonerror="true" in your ant script that calls this process. I do this (at the bottom of my main run-all script) like:

result = Test::Unit::AutoRunner.run(true)
exit 0 if result == nil
exit result

This invokes the same logic as an empty .rb that depends on test/unit - calling autorunner and searching the object space looking for tests to run.

Then you can do a merge on the results of the functional tests as if it was just a normal junit test.