The goal
Be able to unit test database related components without te need to set up and entire RDMS ecosystem. Enabling integration tests to be run by a continuous integration server.
The solution
Create a database on the fly, in-memory. This is achieved by using Maven 2, Springframework and Hibernate together.
Dependencies
I have tested with Derby (former Cloudscape, to be JavaDB). Derby provides an EmbeddedDriver. However files are still created in the filesystem.
HSQLDB should be able to do the trick but I was not able to get the configuration right due to a lack of proper documentation.
H2 delivered the final solution. I added the following dependency to my pom:
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.1.106</version> <scope>test</scope> </dependency>
Test class
I am a big fan of TestNG. Mainly for the ability to group tests. Spring 2.5.x now has excellent annotation based support for TestNG.
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests; import org.springframework.test.context.transaction.TransactionConfiguration; import org.testng.annotations.Test; @Test(groups = { "integration" }) @ContextConfiguration(locations = { "/application-context.xml", "/test-application-context.xml" }) @TransactionConfiguration(defaultRollback=true) public class TestSomeService extends AbstractTransactionalTestNGSpringContextTests { // bunch of test methods }
After the main application-context.xml is loaded I load test-application-context.xml which overrides a couple of bean definitions.
Test application context
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver"/> <property name="url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"/> </bean> <bean id="jpaAdaptor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="false" /> <!-- Let Hibernate generate the DDL for the schema --> <property name="generateDdl" value="true" /> <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" /> </bean> </beans>
Initialize database schema
Hibernate has the ability to create a database schema on the fly the first time the SessionFactory is loaded. This is configured in two places. First the HibernateJpaVendorAdapter needs to be told to generateDdl. Second in the file META_INF/persistence.xml (the default JPA persistence context definition) I set the hibernate.hbm2ddl.auto to create.
<persistence-unit name="some-unit" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <!-- Auto detect annotated model classes --> <property name="hibernate.archive.autodetection" value="class" /> <property name="hibernate.format_sql" value="true"/> <property name="hibernate.hbm2ddl.auto" value="create"/> </properties> </persistence-unit>
References
- TestNG [www.testng.org]
- H2 http://www.h2database.com/
TODO
- Load test data from file