Wednesday, May 23, 2007

NetBeans testing with Groovy

I'm making some progress on my thesis, and as one can expect, when I'm writing code, I need to be writing some unit tests for it. Now, I know that Groovy is an excellent candidate for writing unit tests (better than the traditional JUnit stuff that NetBeans supports out of the box). However, it isn't quite obvious exactly how is one supposed to use and run these Groovy unit tests inside of NetBeans (apart form hacking together a crude solution where you have to add a line to a file, every time you need something to the suite() method). I just want to be able to hit the Alt-F6 button and have all of my tests run like magic : no manual additions to the suite, no tweaking.

So, in the end it worked, with a couple of gotchas:
1. NetBeans only seems to like running JUnit Test cases (when you hit Alt-F6) if and only if the test case name ends with "Test". That's kinda clunky, and as far as I know is not a requirement of JUnit itself. THere is nothing preventing you from executing the unit test individually (e.g. right-click -> run) - it runs like magic, but unless the class name ends with "Test", NetBeans doesn't add it to the bucket of tests to run.

2. The coyote module provides some support for testing in Groovy; however, it is not entirely intuitive exactly how that is done. In effect, if you want things to work nicely, you have to do 2 things:
- first, select a class that you want to test, go to Tools - Groovy Tests - Create Tests. That will basically greate a suite and a test in the $PROJECT/groovy-tests directory, as well as a groovy class in there.

A note a couple of months later, after the completion of the thesis project: Groovy worked great for the unit and integration testing of my project. It was fairly easy to script any of the scenarios that I had in mind, and after I had the general template for working with the groovy tests, it became quite easy to have pretty decent test coverage. Actually, the Groovy tests ended up being one of the important reasons for managing to complete the project after losing all of the work that I had done for the last 1.5 years ( yeah, I know i'm dumb not to have a backup, so, if YOU are working on something that important, DO A BACKUP NOW!!!).

Here is what my setup looks like:



1. I have one Java class for each type of tests that I wrote in Groovy. That is useful to be able to say "Test Project" from the project menu, and have all Groovy Tests executed in a meaningful manner.

2. Each Java JUnit subclass, has something like this in it. In effect, that takes the all Groovy files starting with "Service" and makes test suite out of them. One thing to note is that (slightly inconventiently), when the unit tests are run, all test methods from all groovy files show up under the name of the Java test class e.g.





public static Test suite() throws Exception {
TestSuite suite = new TestSuite("HandlerTests");

suite.addTest(AllTestSuite.suite("/home/polrtex/Docs/UofS_SE/Thesis/Implementation/MvpService/test/groovytest","Service*.groovy"));

return suite;
}


3. Finally, the Groovy test has some test methods in it, which get executed when you run the "Test" command on the project.

One final note on the tests themselves. I was using Spring 2.0 for my project, so I wanted to use the same datasource and service classes that the Spring Framework provides. Now, I knew that there were a couple of supporting Spring test classes (e.g. org.springframework.test.AbstractTransactionalDataSourceSpringContextTests), but I wasn't quite sure how to use them when the test are implemented in Groovy. What I ended up doing was to have a base Java class that extended the Spring test class mentioned above, and then have all of my Groovy tests extend that class. One thing that was interesting to note here was that I had to use the Spring autowire by name option, and the population of protected variables e.g.

class DaoTest extends com.troymaxventurs.mvp.test.MvpBaseTest {
//protected ds;);
protected mvpDAO;
protected mvpDataSource;
DaoTest() {
super("DaoTest")
setPopulateProtectedVariables(true)
setAutowireMode(AUTOWIRE_BY_NAME)
}
}


The reason I needed it to populate the protected variables (and not the bean fields) is that when these Groovy tests were instantiated, Spring tried to populate some Groovy specific public properties (e.g. the metaClass property), and thus, it failed along the way. With the population of protected variables, I could specify exactly what I wanted to have populated, without having to worry about any magic that Spring does to discover what dependencies to inject.