Testing Plugin 0.2 sneakily released (Peter Ledbrook)

, , September 29th, 2008

Peter Ledbrook has “sneakily’ released versions 0.2 and 0.3 of the Grails Testing plugin. You probably have heard about this plugin on the Grails podcast, it promises to make your testing chores a lot easier. The following are excerpts from the announcement made at the grails-user list

Version 0.2

I have released version 0.2 of the testing plugin. This doesn’t
contain either the tag lib stuff or the URL mapping test classes, but
it does include:

  • A bunch of bug fixes
  • getAll() static method for domain classes
  • More render() implementations for controllers
  • Support for mocking command objects
  • Added constructor and “.properties” based data binding
  • “.errors” on domain classes and command objects is a real “Errors” instance
  • save() method calls validate() and adds the new domain instance to
  • the list of test instances
  • “.session” is now an implementation of HttpSession, not a map

svn HEAD contains support for “withFormat” in controllers and it has
basic support for testing tag libraries. Not well tested yet though.
Now all I need is some time to document this stuff.

Version 0.3

Quickly following on, there is now a 0.3 release :)

  • Fixes a bug in ControllerUnitTestCase
  • Supports “withFormat” in controllers
  • Basic support for testing tag libraries, through the new TagLibUnitTestCase

The TagLibUnitTestCase adds an “out”property to the tag, which you can
access and call toString() on to get the content written to the output
writer. It also has support for the render tag - simply check the
“renderArgs” property to find out whether it was called with the right
arguments.

Just thought, if you call “render” more than once in a tag, this won’t
work. For other tags, you will need to do something like:

def tagLibControl = mockFor(MyTagLib)
tagLibControl.demand.link(1..1) { … }

def tagLib = new MyTagLib()
tagLib.myTag([:])

In other words, you’ll have to mock the tag method calls. It supports
the “g.” prefix, but not custom namespaces yet. Any ideas welcome.

Last minute update

Sorry, in the haste to get 0.2 and 0.3 out I think I missed mentioning
a significant change. The validate() method does return a boolean now,
just as it does “in the wild”, i.e. when used in a running
application. You need to access the errors object as you would in
normal code:

def cds2 = new CustomerDataset()
cds2.name = ”
cds2.validate()
assertEquals 1, cds2.errors.errorCount
assertEquals “blank”, cds2.errors[”name”]

The “errors” object on the domain instance is now a proper Spring
Errors instance, but we have overridden property access so that you
can still use notation like “cds2.errors[”name”]” and
“cds2.errors.name”.

You can download the plugin directly from the svn trunk.

Tags: , ,

Functional Test Driven Development with Grails and WebTest (Lee Butts)

, , July 24th, 2008

Original Source

Lee Butts has written a good post on applying functional testing to Grails apps using Canoo WebTest and the WebTest plugin. This is not an introduction to the WebTest plugin nor an article on why functional testing matters, the advantages of both may be clear to many by now, so Lee concentrates in two issues that gave him some trouble, at least on how he wanted the tests to be run. These are

  • the speed of execution of a set of tests
  • how to specify a subset of test to be run (a custom TestSuite if you will)

The Grails WebTest plugin comes with a script which will start your application, run all your test, and shut down the application. This is great for checking your code before checking in or for running on your continuous integration server. However, if you would like to use a WebTest to drive out some functionality it is far too slow.

To get around this I have been using a custom script and parent class for my WebTests. The script is basically a copy of RunWebtest.groovy supplied by plugin with the start/stop application code removed. It also has a small section of code to parse a class patttern and method pattern as arguments. It needs to be placed in the plugins/webtest-0.5/scripts directory of your application so that it can access the required WebTest configuration and resources.

RunWebtestOnly.groovy

This allows for a command such as:

grails run-webtest-only MyDomain edit

which will run all test methods containing the word edit but only those methods found in classes with a name containing the word MyDomain.

That is half of the solution, as it let you specify a subset of tests. One thing to notice is that because the database state is not refreshed between tests it forces you to code in a ’stateless’ manner, some may object on this as functional testing (or integration testing) relies on several components working together, where a predefined state must be set before the actual test. The other half of the solution is to plug in a custom TestSuite so that the subset of tests can be run.

The second part of the solution is the custom parent class for the WebTests. By default, the WebTest plugin requires you to add a suite method to your WebTest to specify the order in which to run the test cases contained within it. This is very useful if there are dependencies between the cases and testA must run before testB for example. To me, this is a bit of a smell that your tests are too fragile. If testA must run before testB in order to set up some state, refactor the code that creates that state into a method and re-use it in testB with unique values so that you can run testB regardless of database state.

Of course there are always exceptions, especially when it comes to keeping test execution time to a minimum, and in reality it may be better to set up common data once and re-use it in several tests. My opinion above is given with a “in an ideal world” disclaimer.

Apologies, I’m getting side tracked! What my custom parent class does is model JUnit in that it automatically builds a suite from all methods beginning in ‘test’. It also applies the class and method filters you gave to the run-webtest-only script which are passed through from Gant via system properties.

MyWebTest.groovy

Now with the help of the WebTestRecorder firefox plugin I can start to drive out a new page, menu item or behaviour.

Finally, following the spirit of TDD, Lee demonstrates a typical scenario for adding new functionality on a particular app. Starting with the WebTestRecorder firefox plugin, he launches a web session recording every single step of the new scenario, tweaking the test code when it makes sense and finally running the failing test (remember a good test starts red), then he simply writes enough code to make the test pass.

Tags: , ,