How to Unit Test Repository with SpringBoot @DataJpaTest

In our previous tutorial, we implemented the soft delete functionality for the user entity and wrote a JUnit test to test the persistent layer. In this tutorial, we are gonna understand how the @DataJpaTest can be used for various scenarios to test the persistence layer.

Introduction

@DataJpaTest focuses only on JPA components. Using this annotation will disable full auto-configuration and instead apply only configuration relevant to JPA tests.

By default,

  • It scans for @Entity classes and configures Spring Data JPA repositories. If an embedded database is available on the classpath, it configures one as well replacing any explicit or usually auto-configured DataSource.
  • Tests annotated with @DataJpaTest are transactional and roll back at the end of each test. If you want to override these settings, then use the @AutoConfigureTestDatabase annotation.
  • SQL queries are logged by setting the spring.jpa.show-sql property to true. You can disable this using the showSql attribute.

If you are looking to load your full application configuration, but use an embedded database, you should consider @SpringBootTest combined with @AutoConfigureTestDatabase rather than this annotation.

When using JUnit 4, this annotation should be used in combination with @RunWith(SpringRunner.class).

Test with Embedded In-memory Database

As described earlier, @DataJpaTest will try to configure an embedded database that is available in the classpath by default. This means we need to include the dependency of any one of the embedded databases in our pom.xml. Otherwise, we will end up with the following error:

Caused by: java.lang.IllegalStateException: Failed to replace DataSource with an embedded database for tests. If you want an embedded database please put a supported one on the classpath or tune the replace attribute of @AutoConfigureTestDatabase.

Once we add an embedded database dependency like h2 in our pom.xml, then we can use the @DataJpaTest annotation to run the tests on the embedded in-memory h2 database.

@DataJpaTest
class UserRepositoryTest {

	@Autowired
	private UserRepository userRepository;
	
	@Autowired
	private RoleRepository roleRepository;
	
	@Test
	void testSoftDelete() {
		// Add a new user
		User user = new User();
		user.setDisplayName("Chinna");
		user.setEmail("[email protected]");
		// Add a role to the user
		Role adminRole = roleRepository.findByName(Role.ROLE_ADMIN);
		user.addRole(roleRepository.findByName(Role.ROLE_USER));
		user.addRole(adminRole);
		user = userRepository.saveAndFlush(user);
		assertEquals(2, user.getRoles().size());
	}
}

Test with Real Database

When we want to run the tests with the real database, then we need to use the @AutoConfigureTestDatabase annotation with replace attribute set to Replace.NONE. This configuration instructs Spring Boot not to replace the application default DataSource.

@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class UserRepositoryTest {

Note: In this scenario, we don’t need to include the dependency of embedded database in the pom.xml since the real datasource will not be replaced with test database.

Test with Auto Configured Test Database

In some scenarios, we may want to customize the test data source configuration as we did in our previous tutorial. In such scenarios, we need to perform the following steps. Let’s assume that we are gonna use the h2 in-memory database for our tests.

Step 1: Add the Database Dependency

Add the h2 database dependency into pom.xml

pom.xml

<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
	<scope>runtime</scope>
</dependency>

Step 2: Define Database Connection Properties

Define h2 database connection properties in src/test/resources/application.properties

src/test/resources/application.properties

#Test Properties
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=MySQL;NON_KEYWORDS=USER
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true

Note: Here, we have created the application.properties file in the src/test/resources directory which will be picked up automatically for auto configuring the test database while executing the JUnit tests. Hence, you don’t need to specify any profile specific properties and activate that profile in the JUnit tests.

Step 3: Use @DataJpaTest with @AutoConfigureTestDatabase

Now, we can write the JUnit tests and run them on the AutoConfigured test database.

@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class UserRepositoryTest {

Note: If you configure the test datasource in a properties file and try to load it with @TestPropertySource(locations = "classpath:test-database.properties"), then @DataJpaTest will not load those properties unless untill you specify @AutoConfigureTestDatabase(replace = Replace.NONE)

Test with Embedded DERBY Database

Apache Derby, an Apache DB subproject, is an open source relational database implemented entirely in Java. If you want to use this one for JUnit tests, then add the following dependency

<dependency>
	<groupId>org.apache.derby</groupId>
	<artifactId>derby</artifactId>
	<scope>runtime</scope>
</dependency>

And use @AutoConfigureTestDatabase annotation with connection attribute set to EmbeddedDatabaseConnection.DERBY

@DataJpaTest
@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.DERBY)
class UserRepositoryTest {

Note: You don’t have to use AutoConfigureTestDatabase to explicitly specify the database connection type if you have only one embedded databse dependency in the pom.xml. i.e., in the classpath.

Test with Embedded H2 Database

H2 is an open source relational database written in Java. If you want to use this one for JUnit tests, then add the following dependency.

<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
	<scope>runtime</scope>
</dependency>

And use @AutoConfigureTestDatabase annotation with connection attribute set to EmbeddedDatabaseConnection.H2

@DataJpaTest
@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)
class UserRepositoryTest {

Test with Embedded HSQLDB Database

HSQLDB is an open source relational database written in Java. If you want to use this one for JUnit tests, then add the following dependency.

<dependency>
	<groupId>org.hsqldb</groupId>
	<artifactId>hsqldb</artifactId>
	<scope>runtime</scope>
</dependency>

And use @AutoConfigureTestDatabase annotation with connection attribute set to EmbeddedDatabaseConnection.HSQLDB

@DataJpaTest
@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.HSQLDB)
class UserRepositoryTest {

Test with TestEntityManager

Data JPA tests may also inject a TestEntityManager bean, which provides an alternative to the standard JPA EntityManager that is specifically designed for tests.

@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class UserRepositoryTest {

    @Autowired
    private TestEntityManager entityManager;
	
	@Test
	void testSoftDelete() {
		// Add a new user
		User user = new User();
		user.setDisplayName("Chinna");
		user.setEmail("[email protected]");
		user = this.entityManager.persistAndFlush(user);
		assertEquals("Chinna", user.getDisplayName());
	}
}

Conclusion

That’s all folks. In this article, we have explored various scenarios for testing the DAO layer using Spring Boot DataJpaTest annotation.

Thank you for reading.

Leave a Reply