26 julio 2011

Using embedded databases in unit tests

Two years ago, I wrote a long blog post -in Spanish- about Test Driven Development. One of the sections of that blog post was about testing code that depends on a database. In short, never use an external database for unit tests.

Using mock objects to simulate the database connection is impractical. A better option is to start and shutdown a embed database. For that matter pure Java SQL databases like HSQL DB are really lightweight, for example a unit test that reads resources from disk usually takes more time than one that uses HSQL in memory.

At the time of that blog post I wrote a small code snippet to start and shutdown HSQL. I used that code snippet many times, but never took the time to create a reusable library for it. Fortunately the Spring guys made it for me :)

Since Spring Jdbc 3 there is an interface to handle embed databases for testing.

If you use Maven, add the dependency to Spring Jdbc (you don't have to use the whole Spring framework if you don't want to) and to HSQLDB:

<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-jdbc</artifactId>
     <version>3.0.5.RELEASE</version>
     <scope>test</scope>
</dependency>
<dependency>
     <groupId>hsqldb</groupId>

     <artifactId>hsqldb</artifactId>
     <version>1.8.0.7</version>
     <scope>test</scope>
</dependency>

Start the embed database before your tests:


@BeforeClass
public static void setUpDatabase() {
     sharedDatabase = new EmbeddedDatabaseBuilder() 

                           .addScript("hsqldb-test-ddl.sql")
                           .build()
}

The EmbedDatabase implements DataSource, so you can pass it to your objects:

hibernateSessionFactory.openSession(sharedDatabase.getConnection());

Shutdown the database after the tests:

@AfterClass
public static void tearDownDatabase() {
    if (sharedDatabase != null) {
        sharedDatabase.shutdown();
    }
}


Usually starting the HSQL server is fast, so you can use @Before and @After (instead of @BeforeClass / @AfterClass).

That's all.