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.<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> OrderPersistenceTest <span style="color: #66cc66;">{</span> <span style="color: #808080; font-style: italic;">/** Fields marked with @ReferenceData will be saved before tests begin. */</span> @ReferenceData <span style="color: #000000; font-weight: bold;">private</span> Product pants = <span style="color: #000000; font-weight: bold;">new</span> Product<span style="color: #66cc66;">(</span><span style="color: #ff0000;">"pants!"</span>, <span style="color: #cc66cc;">12300</span><span style="color: #66cc66;">)</span>; @ReferenceData <span style="color: #000000; font-weight: bold;">private</span> Product socks = <span style="color: #000000; font-weight: bold;">new</span> Product<span style="color: #66cc66;">(</span><span style="color: #ff0000;">"socks!"</span>, <span style="color: #cc66cc;">3000</span><span style="color: #66cc66;">)</span>; @VerifySearch <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #993333;">void</span> findOrdersByProductIncluded<span style="color: #66cc66;">(</span>SpecificationSuite suite<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span> suite.<span style="color: #006600;">specification</span><span style="color: #66cc66;">(</span><span style="color: #000000; font-weight: bold;">new</span> OrderFinder<span style="color: #66cc66;">(</span>pants<span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span> .<span style="color: #006600;">shouldMatch</span><span style="color: #66cc66;">(</span>createOrderWith<span style="color: #66cc66;">(</span>pants, socks<span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span> .<span style="color: #006600;">shouldMatch</span><span style="color: #66cc66;">(</span>createOrderWith<span style="color: #66cc66;">(</span>pants<span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span> .<span style="color: #006600;">shouldNotMatch</span><span style="color: #66cc66;">(</span>createOrderWith<span style="color: #66cc66;">(</span>socks<span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span>; <span style="color: #66cc66;">}</span> @VerifySavesCorrectly<span style="color: #66cc66;">(</span> verifyRelationships=<span style="color: #66cc66;">{</span><span style="color: #ff0000;">"getOrderLines"</span><span style="color: #66cc66;">}</span>, ignoreProperties=<span style="color: #66cc66;">{</span><span style="color: #ff0000;">"getClass"</span><span style="color: #66cc66;">}</span><span style="color: #66cc66;">)</span> <span style="color: #000000; font-weight: bold;">public</span> Order orderWithDifferentProducts<span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span> Order order = <span style="color: #000000; font-weight: bold;">new</span> Order<span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span>; order.<span style="color: #006600;">addProduct</span><span style="color: #66cc66;">(</span><span style="color: #cc66cc;">10</span>, pants<span style="color: #66cc66;">)</span>; order.<span style="color: #006600;">addProduct</span><span style="color: #66cc66;">(</span><span style="color: #cc66cc;">2</span>, socks<span style="color: #66cc66;">)</span>; <span style="color: #000000; font-weight: bold;">return</span> order; <span style="color: #66cc66;">}</span> @ReferenceData <span style="color: #000000; font-weight: bold;">private</span> Category supercategory = <span style="color: #000000; font-weight: bold;">new</span> Category<span style="color: #66cc66;">(</span><span style="color: #ff0000;">"parent"</span><span style="color: #66cc66;">)</span>; <span style="color: #808080; font-style: italic;">/** This will verify that category.subcategory[*].parent is also set correctly. */</span> @VerifySavesCorrectly<span style="color: #66cc66;">(</span> verifyRelationships=<span style="color: #66cc66;">{</span><span style="color: #ff0000;">"getSuperCategory"</span>, <span style="color: #ff0000;">"getSubCategories"</span><span style="color: #66cc66;">}</span><span style="color: #66cc66;">)</span> <span style="color: #000000; font-weight: bold;">public</span> Order categoryWithRelationships<span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span> Category category = <span style="color: #000000; font-weight: bold;">new</span> Category<span style="color: #66cc66;">(</span><span style="color: #ff0000;">"this category"</span>, supercategory<span style="color: #66cc66;">)</span>; category.<span style="color: #006600;">addSubCategory</span><span style="color: #66cc66;">(</span><span style="color: #ff0000;">"subcategory 1"</span><span style="color: #66cc66;">)</span>; category.<span style="color: #006600;">addSubCategory</span><span style="color: #66cc66;">(</span><span style="color: #ff0000;">"subcategory 2"</span><span style="color: #66cc66;">)</span>; <span style="color: #66cc66;">}</span> <span style="color: #808080; font-style: italic;">/** This is all the configuration that is needed! */</span> <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #aaaadd; font-weight: bold;">String</span><span style="color: #66cc66;">[</span><span style="color: #66cc66;">]</span> MAPPING_FILES = <span style="color: #66cc66;">{</span> <span style="color: #ff0000;">"com/brodwall/webshop/Category.hbm.xml"</span>, <span style="color: #ff0000;">"com/brodwall/webshop/Product.hbm.xml"</span>, <span style="color: #ff0000;">"com/brodwall/webshop/Order.hbm.xml"</span>, <span style="color: #66cc66;">}</span>; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> Test suite<span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span> PersistencetestSuite suite = <span style="color: #000000; font-weight: bold;">new</span> PersistenceTestSuite<span style="color: #66cc66;">(</span>OrderPersistenceTest.<span style="color: #000000; font-weight: bold;">class</span>, mappingFiles<span style="color: #66cc66;">)</span>; <span style="color: #808080; font-style: italic;">// We can turn on how the tests are being executed:</span> suite.<span style="color: #006600;">runOnOracle</span><span style="color: #66cc66;">(</span><span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">)</span>; suite.<span style="color: #006600;">runOnHsqlDB</span><span style="color: #66cc66;">(</span><span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">)</span>; suite.<span style="color: #006600;">runOnInMemory</span><span style="color: #66cc66;">(</span><span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">)</span>; suite.<span style="color: #006600;">verifyFinders</span><span style="color: #66cc66;">(</span><span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">)</span>; <span style="color: #66cc66;">}</span> <span style="color: #66cc66;">}</span>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. Java