"COMPUTER POWER TO THE PEOPLE! DOWN WITH CYBERCRUD!" - Theodor Nelson
Thursday, December 29, 2005
Testing Abstract Code
I've been working on some java code lately and I came across something interesting. I have a set of domain objects that I wanted to make persistable via Hibernate. Now, these domain objects are meant to be used by other folks and they might want to map their Hibernate objects differently. So, I wanted to provide the support and maybe an example of how to map the objects. The problem was that I didn't want to bundle Hibernate just so that I could test the mappings.
What's a programmer to do? Well, to be Hibernate persistable, a class must have a default constructor and accessors for each field. Why not test for that? So, I quickly whipped up some code to iterate through the class path and find each of my domain objects. It then checks each class for the constructor and that each field has accessors. Wonderful. But, how do I know they work?
In the process of verifying everything, I had all of the reflection objects that I needed to verify that they worked as well. So, I invoke the default constructor and make sure no errors ensue. I then set/get each field with sample values and verify the results. If at anytime, an error happens, I output a reason and the test fails.
Now, I have a test that will keep me honest and tell me if I ever do something stupid to break my mappings. I can also enforce standards by testing if I wanted to. This is just another example of the power of meta-testing.
The design was simple. I had an object called ClassGenerator that was responsible for traversing the class path and providing class objects to an abstract method. It walked directories and jars respectively. The next object was a ClassFilter that would be given to the ClassGenerator to work much like FileFilter does. I did this so I could create a filter for my domain objects and outright reject classes that were out of my control. The last object was a Verification object that was responsible for making sure a class was correct (default constructor, all accessors worked, etc). The test is where everything was put together. He creates an inner class that subclasses ClassGenerator and hands it a DomainClassFilter. The inner class simply creates a new Verification object for each class passed into it and asks if the class is valid. If not, the tests fails and reasons are given why.
It was great to use this test to make sure I had done all of the mappings correctly and had not forgotten anything. The power of reflection compels me!