Archive for August, 2008

“Wow”-talks

I just watched another amazing talk from the TED conference. Spencer Wells is a natural public speaker. He talks about where we all, as a species, came from. Amazingly enough, everyone who is alive today share a common ancestor in Africa no more than about 2000 generations, or 60,000 years ago. Wells describes the fascinating questions and their answers, as we know them today.

The TED conference is full of remarkable talks. Here are some of my absolute favorites:

Read the rest of this entry »

Comments

Top three lessons that improved our process

Looking back at my projects for the last two years, we’ve had a tremendous improvement in the way we’re working. There are many things that we have done to make it better, and I’m be hard pressed to pick just three things I’ve learned. After much consideration, my favorites are: Partial production; Whole team; Requirements = Tests.

Read the rest of this entry »

Comments

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.

Comments

Creative Commons Attribution 3.0 Unported
This work is licensed under a Creative Commons Attribution 3.0 Unported.