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 !!