In this tutorial, you will learn to implement an integration test of the JPA and Hibernate data layer in Spring Boot by using @DataJPATest
annotation with in-memory database
@DataJPATest
provides the following features
Configure the in-memory test database
Auto-scan
@Entity
classesAuto configure Spring Data JPA, Hibernate and Data Source
Turn on SQL logging
Project dependencies
Include spring-boot-starter-test
and hsqldb
into your pom.xml
file
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
spring-boot-starter-test
contains some testing support libraries such as JUnit, Spring Test + Spring Boot Test, Mockito, AssertJ, Hamcrest and JsonPath
Define the test class
Run the tests with @RunWith(SpringRunner.class)
and @DataJPATest
Use
@RunWith(SpringRunner.class)
class annotation to tellJUnit
to run the unit tests in Spring's testing supportsUse
@DataJPATest
class annotation to test JPA and Hibernate layer
Inject dependencies with @Autowired
- Inject
TestEntityManager
field
@Autowired
private TestEntityManager testEntityManager;
TestEntityManager
is designed for tests, provides an alternative to the JPA standard EntityManager
- Inject the JPA Repository you want to test, for example
@Autowired
private ProductRespository productRespository;
Verify the test result with AssertJ's assertThat(..).
- Prefer AssertJ's
assertThat
to verify the test result for more readability, for example
// when
List<Product> products = productRespository.findAll();
// then
assertThat(products).hasSize(1);
Implementation example
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit4.SpringRunner;
import java.math.BigDecimal;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@DataJpaTest
public class ProductRepositoryTest {
@Autowired
private TestEntityManager testEntityManager;
@Autowired
private ProductRespository productRespository;
@Before
public void setUp(){
// given
Product product = Product.builder()
.name("P1")
.description("P1 desc")
.price(new BigDecimal("1"))
.build();
testEntityManager.persist(product);
}
@Test
public void whenFindByName_thenReturnProduct() {
// when
Product product = productRespository.findByName("P1").get();
// then
assertThat(product.getDescription()).isEqualTo("P1 desc");
}
@Test
public void whenFindAll_thenReturnProductList() {
// when
List<Product> products = productRespository.findAll();
// then
assertThat(products).hasSize(1);
}
}
@DataJPATest
by default will begin a new transaction before and roll back it after running a test method. You should see something like this in the console when running the test
Began transaction (1) for test context [DefaultTestContext@43ee72e6 testClass = ProductRepositoryTest... testMethod = whenFindByName_thenReturnProduct@ProductRepositoryTest...
...
Rolled back transaction for test: [DefaultTestContext@43ee72e6 testClass = ProductRepositoryTest... testMethod = whenFindByName_thenReturnProduct@ProductRepositoryTest...
Conclustion
In this article, we learned using @DataJPATest to implement integration test for the data access layer in Spring Boot. You can find the source code on GitHub