Wednesday, 2 March 2016

JUnit + H2 + Spring: Unit testing with in-memory database

Ussually web applications developed with Spring use a database for storing and reading data. Creating unit tests that are A TRIP (See this unit testing cheat sheat) cand turn out to be kind of painfull.

Luckyly for us we can achive that easily with Junit, Spring, Maven and H2. We will use an in-memory database that Spring will create and populate for us before the tests. The database will always be in a known state before and while running the tests, so we don't get nasty fails because of inconsistent data.

pom configuration
In your src/test/resources create a file named test-config.xml.
In this file we are creating a database in the jdbc:embedded-database tag. Spring will create an H2 database instance and execute the scripts test.sql and data.sql when setting up the context.  

You also need to create the file src/test/resources/META-INF/h2-persistence.xml. Notice that there are no connection configuration on the persistence file.

Database for testing
Create a test.sql and a data.sql files with the ddl and the data for your tests. Notice that h2 sql has it's own markup so you may need adjust the sql generated from your db.  

The tests You just need to annotate your test with @RunWith(SpringJUnit4ClassRunner.class) and @ContextConfiguration(locations = { "classpath:test-config.xml" }). This will get running the spring context for the tests, and the h2 database with it.

Using @Transactional
If you annotate a test with @Transactional the entire unit test will be inside one transaction thath will be rolledback after the test, keeping the database data clean after the test.

Service and DAO tip
If your Service layer is annotated with @Transactional and your Dao layer isn't (daos shouldn't have  @Transactional)  test just one layer on each test case. For example, if you are testing the PartyService don't use the PartyDAO for the asserts, as the PartyDAO won't see changes created at the service functions.

You can view a full working example in wrex