SQL Zone is brought to you in partnership with:

Software Engineer And co-founder of nerdability.com. Having spent 6 years in a leading tech consultancy I am now working in startups in London. Interested in java, groovy, spring, js, android and anything else that looks fun. Rob has posted 6 posts at DZone. You can read more from them at their website. View Full User Profile

Hibernate + Spring - Testing the Data Access Layer with an In Memory Database

07.20.2011
| 12523 views |
  • submit to reddit

For some time I have been working on developing a Java web app using Spring MVC & Hibernate, and as many will have discovered, this throws up lots of questions with unit testing. To increase my coverage (and general test confidence) I decided to implement some tests around the DAO layer. Up untill now, the DB access had been mocked out, and whilst some purists will argue that these are strictly "Integration tests" rather than unit tests, I decided to go ahead with the.

As I didn't want to be messing around with going near my dev DB, or worrying about dropping my dev data everytime I run a test I decided to test the DAO layer using in memory DB (HSQL), so here's how its done:

First, I added the dependency to my POM so the HSQL JARs were downloaded:

<dependency>
<groupid>hsqldb</groupId>
<artifactid>hsqldb</artifactId>
<version>1.8.0.10</version>
<type>jar</type>
<scope>test</scope>
</dependency>



Next, in my Persistence.xml I added a new Persistence Unit, that would point my tests to my in-mem DB

<persistence-unit name="testingSetup">
<properties>
<property name="hibernate.archive.autodetection" value="class, hbm"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:butterfly"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>

 

 

Important points to note here are that the database name can be anything you like (well, as long as you have the url jdbc:hsqldb:mem: ..). Also, the username must be "sa" and the password "". There is no manual install needed, or explicit DBs created, as long as you have the JAR in your project everything will be handled for you.

Next, I copied my regular applicationContext.xml to src/test/resources, as I needed to configure this to point to my new Persistence Unit defined (and new data source)

    <context:property-placeholder location="classpath*:META-INF/spring/*.properties" />
<context:spring-configured />
<context:component-scan base-package="com.tmm.enterprise.microblog">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation" />
</context:component-scan>

<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="applicationController" class="com.tmm.enterprise.microblog.service.ApplicationService"></bean>

<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="testingSetup"/>
</bean>





As you can see, I have updated my Entity Manager Factory Bean to be using my newly created Test Persistence unit - this means any time Spring is fired up using the context definition, it will be pointing to my in-mem DB - Now I have configured everything, I am ready to start testing.

I started by writing an abstract test class - I used this to define my common @Before method (I needed to setup a common "test" user to allow db updates to complete), but the important thing here is the annotations on the class

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/test-applicationContext.xml"})
@Transactional
public abstract class AbstractServiceTest {



These annotations tell the tests that they are running with the Spring junit runner, and to use my newly created test-applicationContext.xml. The @Transactional is neccesary so we know to roll back all data persisted during the tests at the end of each test (we dont want test data leaking in to other tests and potentially affecting the outcome).

Now its just a case of writing the tests, here is an example of a test:

public class AccountServiceDbTest extends AbstractServiceTest{

@Autowired
AccountService service;

@Test
public void testFindAllAccounts() {
List<account> accs = service.findAllAccounts();
assertEquals("Check DB is empty first", 0, accs.size());
Account a = new Account();
a.setUserName("robb");
a.setPassword("password");
service.storeAccount(a);
accs = service.findAllAccounts();
assertEquals("check Account has been created", 1, accs.size());
}

}




The test checks that nothing is in the DB, then persists the new account to the table (all in-memory) and then checks the size to make sure it has been created correctly. At the end of the test the transaction is rolled back, so this will always work!

Another interesting point, is as I have defined the Spring context in the Abstract class, my tests are all now Spring-managed, which means I can simply use the @Autowired annotation to autowire other Spring classes such as Service classes (these have my DAOs etc in).

 

And Thats It! I was pleasantly suprised how easy it was to get up and running.

 

This was originally posted on my blog at : http://automateddeveloper.blogspot.com/

Published at DZone with permission of its author, Rob Hinds.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)