Integration testing Spring Data JPA

Integration testing at the data layer is first. I chose to start with this for two reasons:
First is for those that love test driven development (TDD). When starting a project I suggest starting with the domain objects and build a solid object model for the app. And since most models are just getters/setters there is not much to test out of the gate. So the next logical step is to test how the models interact with the database and each other. It will save a lot of time to analyze the base queries and relationship mapping before getting too far along.

The second is for those who already have an app without tests or save tests for “hardening sprints” as the last step. Once you solve the Spring context for testing then the rest gets easier. Plus if you run out of time at least the tests will catch domain changes not rolled out to the database.

This post attempts to cover the basics in setting up unit tests that run in the Spring context allowing integration testing of Spring Data JPA interfaces. The tests will be transactional (all data changes are rolled back after the test) and integrated with the project database. This should be for any custom DAO methods, queries and operations. If you are using Spring Data JPA for the boilerplate crud, paging or sorting interface then this won’t help. I don’t encourage testing other peoples/projects code unless you are trying to insulate from version changes or how it’s integrated into the app. That being said the first example for a crud operation.. saving. It a good starting place to prove it works. Rollback can be toggled to experiment and it’s simple.

Application SetupThese tests are built on the Spring Data JPA example in a previous post. A jUnit dependency was added to the pom.xml

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>

The first step is to create the test sources per maven spec and create the test file “/src/test/java/com/luckyryan/sample/dao/UserDaoIntegrationTest.java”

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:applicationContext.xml","classpath:applicationContext-dao.xml"})
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class UserDaoIntegrationTest {

    @Autowired
    UserDao userDao;

    @Test
    public void testCreateUser() {
        User user = new User();
        user.setEmail("unitTest@test.com");
        user.setFirstName("unitTestFirstName");
        user.setLastName("unitTestLastName");

        assertNull(user.getId());

        user =  userDao.save(user);

        assertNotNull(user.getId());
        assertTrue(user.getId() > 0);
    }
}
Java Config Version
@ContextConfiguration(loader=AnnotationConfigContextLoader.class,classes={dbConfig.class})
The appConfig.class was not included for this test because it is unnecessary. It has definitions that would normally belong in the servlet.xml file that don’t work in this context. If I needed only a few beans from that file then I would create a test only version in the test source path and include it here.


@RunWith
is a JUnit annotation that will instruct the test to be invoked with Springs class “SpringJunit4ClassRunner.class” instead of the JUnit default class. This makes it possible to process the Spring annotations for the file. An alternate method would be to extend SpringJunit4ClassRunner on the test class. That can be helpful for base test classes.

@ContextConfiguration
is for Spring so it knows which config files to load. Note: you need to include any and all Spring config classes here that your tests will depend on. If not you will get bean not found errors or incomplete mappings. By default this will try to load “classpath:/com.luckyryan.sample.dao/UserDaoIntegrationTest-context.xml” if no mappings are specified. I like to include the context for clarity but mentioned here as an FYI if you have a custom context and you see conflicts.

@Transactionl puts the class in the Spring transaction which will make the next annotation useful.

@TransactionConfiguration(defaultRollback = true) this will rollback any db changes at the end of the test. This is nice if you need to preserve test state between tests. This can be set to false to experiment and create test rows. Note: with MySql you won’t see the data in the table during the test because it’s in a transaction.

The @Autowired DAO is the Spring Data JPA interface for the project. Then the test will create a domain object and attempt to persist it through the interface.

That’s about it for this test, run it and it should be all green. From here just add methods as they are added to the interface.


public interface UserDao extends CrudRepository<User,Long> {

	User findByEmail(String emailAddress);

}

Then test accordingly…


@Test
  public void testFindUserByEmail() {

	  String email = "test@test.com"

      user = userDao.findByEmail(email);

      assertTrue(user.getId() > 0);
      assertEquals(email, user.getEmail);
  }

Seems simple but try this test with two records that have the same email. You’ll see there is an assumption in the code that it will always return one result. This will throw a DataAccessException when more than one record is found.

Testing Series
This post is one in a series about end to end testing of Spring MVC applications. If you are interested in other levels of application testing then check out the series index here.

Sample Spring MVC + Test Suite (8416 downloads)

One Response

  1. Vishwas Shashidhar July 30, 2014

Leave a Reply

Your email address will not be published. Required fields are marked *