Monday, December 14, 2009

Hibernate & DBUnit

I finally got the combination of Hibernate, DBUnit, Derby, Spring and JUnit working to my satisfaction.

We developed a test Jar which includes a ZIP file containing a full Derby database with all the schema and 'lookup' data contained in our production Oracle instances. This was done in order to remove the dependence on the test Oracle instances for unit testing of our ORM mappings. However, the problem remained of unit test performance. Individual unit tests classes can have 'before' and 'after' functions that are run around each and every test inside that class. They can also have 'beforeClass' and 'afterClass' functions that are executed for the entire group of tests contained within the class. However, neither of these is really suitable for the problem of decompressing a zip file and initializing a Derby embedded DB driver. Its a very expensive operation that you really only want to have happen once for the entire set of test classes.

Up until recently, we got around this by having all the test classes derive from a common base class, which had a beforeClass static method that would do all the initialization. However, this actually had to be done based on the value of a static boolean variable, since that beforeClass function would be called many times (once for each derived concrete test class). In addition to the ugliness of this approach, it didn't lend itself to a mechanism for cleanup. While you can have an afterClass method, this method would be called many times for the same reason as the beforeClass method, and if you put cleanup code there you might be cleaning up the state which the next test class needs. There's no way to know if a particular call to the afterClass method is the final call.

All this got fixed when I learned about the use of unit test suites. A suite is pretty much what it sounds like, a collection of unit test classes, with its own encompassing beforeClass and afterClass methods which will each be run once for the suite, regardless of how many test classes it contains. I'd seen suite usage before from time to time but never really paid it much attention, and when I looked, I found documentation on using suites in JUnit suprisingly sparse. Much of what is available is related to the JUnit 3.8.x style of unit testing, not the new annotation based testing. Further, even the 'surefire' testing plugin for Maven doesn't work well with suites unless you force a particular plugin version in your POM.

Regardless, once you overcome those obstacles, the use of a Suite for pan-test class setup and cleanup ends up being valuable.

For those interested the suite is annotated like this:
@RunWith(org.junit.runners.Suite.class)
@SuiteClasses({ ContentListRetrieve.class, GalleryRetrieve.class, ImageRetrieve.class, ImageSetRetrieve.class, StoryRetrieve.class} )
public class SwiftCoreSuite extends SwiftBaseSuite {
Because we actually have multiple related ORM jars, we still break up the suites into base and derived classes. The SwiftBaseSuite class is responsible for initializing the spring context, decompressing the Derby database and creating a JDBC driver pointing to it. The SwiftCoreSuite class is responsible for injecting the test data for the unit tests in this particular jar and providing the suite annotations.

The relevant Maven POM sections look like this:




maven-surefire-plugin
2.4.3


**/*Suite.java






No comments:

Post a Comment