Spring Boot @DataJpaTest

Learn about Spring Boot @DataJpaTest annotation and how to use it for testing JPA repositories marked with @Repository annotation.

1. @Repository annotation

In the spring framework, @Repository is one of the stereotype annotations which enable annotated classes (DAO) to be discovered and registered with the application context.

We are creating one such EmployeeRepository and we will be writing a few JUnit tests to test it.

@Repository
public interface EmployeeRepository
        extends JpaRepository<EmployeeEntity, Long> 
{
  //...
}

2. @DataJpaTest Annotation

In Spring boot applications, we can use @DataJpaTest annotation that focuses only on testing the JPA components. @DataJpaTest will disable full auto-configuration of the application context and instead apply only configuration relevant to JPA components and tests.

By default, it scans for @Entity classes and configures Spring Data JPA repositories annotated with @Repository annotation.

2.1. Embedded Database

If an embedded database is available on the classpath, it configures one as well. Use @AutoConfigureTestDatabase to override this behavior. For example, to run the tests against an application configured real database, use Replace.NONE.

@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
public class TestAppData {
   // ..
}

2.2. SQL Logs

To log SQL queries, set the spring.jpa.show-sql property to true.

spring.jpa.show-sql = true

2.3. Transactions

By default, data JPA tests are transactional and roll back at the end of each test. To disable this feature, use Propagation.NOT_SUPPORTED.

@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class TestAppData {
   // ..
}

2.4. TestEntityManager

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

Note that when using TestEntityManager, tests should be running in a transaction. The @DataJpaTest includes @Transactional annotation in it, so we do not need to do anything extra for it.

@DataJpaTest
public class TestAppData {
  
  @Autowired
  private TestEntityManager em;

  //..
}

2.5. JUnit Runner

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

@RunWith(SpringRunner.class)
@DataJpaTest
@Import(JpaConfig.class)
public class TestAppData {
  //...
}

When using JUnit 5, this annotation already contains the statement @ExtendWith(SpringExtension.class), so no additional runner definition is required.

@DataJpaTest
@Import(JpaConfig.class)
public class TestAppData {
  //...
}

3. Demo

Given TestBootstrappingEntityManager class tests the EmployeeRepository which is of type JpaRepository and is used to store and retrieve EmployeeEntity instances from underlying databases.

import com.howtodoinjava.demo.data.EmployeeRepository;
import com.howtodoinjava.demo.data.entity.Employee;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
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.context.annotation.Import;

@DataJpaTest
@Import(JpaConfig.class)
public class TestBootstrappingEntityManager {

  @Autowired
  private TestEntityManager em;

  @Autowired
  private EmployeeRepository repository;

  @Test
  public void contextLoads() {
    Assertions.assertNotNull(em);
  }

  @Test
  void verifyBootstrappingByPersistingAnEmployee() {
    Employee emp = new Employee();
    emp.setEmail("demo-user@email.com");
    emp.setFirstName("demo");
    emp.setLastName("user");

    Assertions.assertNull(emp.getEmployeeId());
    em.persist(emp);
    Assertions.assertNotNull(emp.getEmployeeId());
  }

  @Test
  void verifyRepositoryByPersistingAnEmployee() {
    Employee emp = new Employee();
    emp.setEmail("demo-user@email.com");
    emp.setFirstName("demo");
    emp.setLastName("user");

    Assertions.assertNull(emp.getEmployeeId());
    repository.save(emp);
    Assertions.assertNotNull(emp.getEmployeeId());
  }
}

Watch the program output in the console. We will find that only JPA-related configuration has been loaded into context and then tests execution start from there.

Drop me your questions related to Spring Boot @DataJpaTest annotation as discussed above.

Happy Learning !!

Sourcecode on Github

Was this post helpful?

Join 8000+ Awesome Developers, Like YOU!

Leave a Comment

About HowToDoInJava

This blog provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions, and frequently asked interview questions.