Did the in-memory database integration testing work as expected?
On my previous post about integration testing with an in-memory database without hibernate I was in the process of finding out which frameworks to use and which in-memory databases to use.
We are now using h2database with Unitils and generated sql schemas for integration testing. H2Database was chosen because it supported most of the syntax and functions/procedures we have in our Firebird database.
The major challenges with this approach is maintainability with the sql schema. I haven't found a good solution for this yet, so we have to update the test schema every time there are changes in the database schema.
Further I will show you a short summary of the setup:
Add some maven dependencies
<dependency> <groupId>org.unitils</groupId> <artifactId>unitils-dbunit</artifactId> <version>3.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-orm</artifactId> <version>3.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.unitils</groupId> <artifactId>unitils-dbmaintainer</artifactId> <version>3.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.2.132</version> </dependency>
Unitils needs a property file to figure out the database connection parameters and paths. Stuff it in your resources folder and call it unitils.properties
unitils.modules=database, dbunit, easymock, spring database.driverClassName=org.h2.Driver database.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 database.dialect=h2 database.userName=sa database.password= database.schemaNames=public database.storedIndentifierCase.h2=auto database.identifierQuoteString.h2=auto org.unitils.core.dbsupport.DbSupport.implClassName.h2=com.testing.common.database.H2DbSupport org.dbunit.dataset.datatype.IDataTypeFactory.implClassName=org.dbunit.ext.h2.H2DataTypeFactory updateDataBaseSchema.enabled=true org.unitils.dbmaintainer.script.ScriptSource.implClassName = com.testing.testutils.ClasspathScriptSource dbMaintainer.script.locations=classpath:/dbscripts dbMaintainer.autoCreateExecutedScriptsTable=true dbMaintainer.fromScratchEnabled=false dbMaintainer.keepRetryingAfterError.enabled = true dbMaintainer.cleanDb.enabled = false dbMaintainer.script.fileExtensions=sql dbMaintainer.generateDataSetStructure.enabled=true dbMaintainer.updateSequences.enabled=true dataSetStructureGenerator.xsd.dirName=target/xsd
As you may have noticed in the above property file, there are two java implementations. One is to get support for h2database and the other is for getting the paths for the schemas from classpath.
We need to fill the h2database with some tables. Infact i wanted the same schema as i production. I managed to export the firebird database schema and hack away some none working syntax.
The path to the data is defined in unitils.properties: dbMaintainer.script.locations=classpath:/dbscripts
In this path you have to put all your .sql schema files which typically contains a set of create table, insert into statements.
Last but not least, the java test implementation. First the example.
@RunWith(UnitilsJUnit4TestClassRunner.class) @SpringApplicationContext(value = {"/testContext-service-integrationtests.xml"}) @DataSet(value = {"CommonTestData.xml", "SubscriptionServiceImplIntTest.xml"}) public class EmailServiceImplIntTest { @SpringBean("subscriptionService") private SubscriptionService subscriptionService; @Test @ExpectedDataSet(value = "SubscriptionServiceImplIntTest.xml") public void testGetSubscriptionByCustomerId() throws Exception { List<Subscription> subscriptions = subscriptionService.getSubscriptionByCustomerId(152); assertTrue(subscriptions.size() > 0); } }
A little explanation to the code above. The test class is annotated with a runner for Unitils, a spring context as I am running spring for my beans and a DataSet annotation. The DataSet annotation defines the test data for your test. I'll give you an example below. I also use unitils annotation for injecting my service.
<?xml version='1.0' encoding='UTF-8'?> <dataset> <subscription id="1" customerId="152" addressId="1" product="Test product"/> </dataset>
I could go into detail about this, but I am not super happy with the solution. It works, but it lacks a bit automation. How can I update the database schema automatically? Has anyone solved this need for integration tests another way? (not you guys fortunate enough using hibernate)
Related posts: