A small library to test persistent objects
When the building blocks of your program fail and you don’t notice, the problem can be very hard to diagnose. In most of my projects, the building blocks are the persistent objects. Using Hibernate makes it easy to create a data access layer, but if you don’t watch out, errors can sneak into equals
or hashCode
, bidirectional relationships or properties that for some reason don’t get persisted correctly. Or the code you use to search for your objects can be wrong.
To make sure I find these problems early, I’ve always written tests to ensure correct behavior. But these tests, even though they were conceptually simple, often got cluttered and hard to maintain. To address this, I have written myself a small library that lets me focus on the intention behind the test. The library isn’t quite ready for public consumption, but I’m hoping that you’ll find it interesting.
public class OrderPersistenceTest {
/** Fields marked with @ReferenceData will be saved before tests begin. */
@ReferenceData private Product pants = new Product("pants!", 12300);
@ReferenceData private Product socks = new Product("socks!", 3000);
@VerifySearch
public void findOrdersByProductIncluded(SpecificationSuite suite) {
suite.specification(new OrderFinder(pants))
.shouldMatch(createOrderWith(pants, socks))
.shouldMatch(createOrderWith(pants))
.shouldNotMatch(createOrderWith(socks));
}
@VerifySavesCorrectly(
verifyRelationships={"getOrderLines"},
ignoreProperties={"getClass"})
public Order orderWithDifferentProducts() {
Order order = new Order();
order.addProduct(10, pants);
order.addProduct(2, socks);
return order;
}
@ReferenceData private Category supercategory = new Category("parent");
/** This will verify that category.subcategory[*].parent is also set correctly. */
@VerifySavesCorrectly(
verifyRelationships={"getSuperCategory", "getSubCategories"})
public Order categoryWithRelationships() {
Category category = new Category("this category", supercategory);
category.addSubCategory("subcategory 1");
category.addSubCategory("subcategory 2");
}
/** This is all the configuration that is needed! */
private static String[] MAPPING\_FILES = {
"com/brodwall/webshop/Category.hbm.xml",
"com/brodwall/webshop/Product.hbm.xml",
"com/brodwall/webshop/Order.hbm.xml",
};
public static Test suite() {
PersistencetestSuite suite = new PersistenceTestSuite(OrderPersistenceTest.class, mappingFiles);
// We can turn on how the tests are being executed:
suite.runOnOracle(true);
suite.runOnHsqlDB(true);
suite.runOnInMemory(true);
suite.verifyFinders(true);
}
}
The test suite will actually run each of the @VerifySavesCorrectly and @VerifySearchResult tests on several implementations of the data storage: Oracle with Hibernate to simulate production, HSqlDb in memory with Hibernate to test the configuration faster, and an in-memory Fake implementation of the data store that is used for other unit tests. That way, I know that the behavior is consistent. If I was to implement, say a JDO storage mechanism, I would easily be able to verify that all my persistence logic works. It’s a small and sweet little library, but I’m quite happy with how the tests look. I humbly submit this as an example of intent-driven code. I hope you like it.