Friday, June 09, 2006

Sharing initialization across Unit Tests

In principle unit tests should be isolated from each other to ensure that running one unit test does not influence another. There is however, I believe, a case where having a shared initialization between unit tests can make a lot of sense. Whenever a time consuming initialization needs to take place, and when one can ensure that the state of the initialized environment does not influence in any way the tests, then it is really important to share initialization. One of the goals of unit testing is to make it easy to test, to promote a test-often approach and that will conflict with long initialization times. An initialization that takes a couple of seconds, although very acceptable for a running application is not acceptable at all for unit testing. If you do follow the test-often approach, you will be building a large number of tests (not hard to admit you will have several dozens, hundreds of tests). Multiply that by the initialization cost and testing becomes unbearable.

Example of the above. I have been working for sometime with WebWork+Spring+Hibernate and using JUnit for unit testing integrated in the build/deployment process via Ant. The startup time for the system is around 8 seconds (still way lower than a full J2EE application server startup time ;-)...but after even a mere 12 tests it becomes impossible to have to wait for a simple test run. By isolating the initialization of WebWork+Spring+Hibernate in a shared initialization class, I was able to reduce the overall tests run time by a huge factor. Somewhere from 104s to 12s in my simple (very simple) case of 12 tests.

The solution for me, I create a singleton class that isolates all shared initialization then I make sure all tests run via ant using the task batchtest with forking enabled and with forkmode set to 'perBatch' (see http://ant.apache.org/manual/OptionalTasks/junit.html) and voila, I get shared initialization and a huge reduction in test running.

After looking online for similar issues, I found the link http://beust.com/weblog/archives/000082.html that talks a bit about this same issue confirming my worries and validating this approach.

My belief in unit testing restored, I continue my development with my nice safety net in place...

2 comments:

Anonymous said...

You should definitely check out TestNG then (http://testng.org), which gives you much more flexibility in how your tests can be configured.

Francisco Assis Rosa said...

Interesting...not the first time I bump into a mention to TestNG. Have also heard some podcast about it...sounds pretty cool...will definitely add it to my list of things to look at pretty soon...and will add my comments to the blog once I play with it.

Thanks for the feedback!