@DataJpaTest는 JPA, 데이터베이스 관련 설정만 최소한으로 로드하여 레포지토리/엔티티를 테스트하는 어노테이션이다.
- 임베디드 데이터베이스를 자동 구성해주기 때문에 외부 데이터베이스를 사용하지 않아도 된다.
- Application Context에 JPA, 데이터베이스 관련 클래스들을 자동으로 로드해준다.
- 테스트가 끝날 때마다 데이터베이스 상태가 자동으로 rollback된다.
위 내용에 대해 더 자세히 알아보자!
1. 기본적으로 In-memory Embedded Database H2를 사용
@DataJpaTest는 테스트 실행 시 In-memory Embedded Database H2를 기본적으로 사용한다.
임베디드 데이터베이스는 애플리케이션 외부의 데이터베이스(MySQL 등) 없이 테스트 실행 중 메모리에서 동작하는 가벼운 데이터베이스이다. Spring Boot는 테스트 실행 시점에 classpath에 임베디드 데이터베이스 관련 라이브러리가 존재하면 자동으로 jdbc:h2:mem:testdb URL을 가진 인메모리 데이터베이스를 생성하고, 테스트가 끝나면 삭제한다. 임베디드 데이터베이스는 속도가 빠르고 설치도 필요없어서 테스트에 가장 적합하다.
외부 데이터베이스 환경에서 테스트하고싶으면 @AutoConfigureTestDatabase를 통해 임베디드 데이터베이스를 비활성화하거나, @DataJpaTest 대신 @SpringBootTest를 사용하면 된다.
@DataJpaTest
@AutoConfigureTestDatabase(replace=Replace.NONE) //임베디드 DB 사용 해제
class ExampleRepositoryTests {
// ...
}
2. auto-configure되는 클래스들
@DataJpaTest의 auto-configuration 목록에서 어떤 객체가 자동으로 Bean으로 등록되어있는지 알 수 있다.
애플리케이션에 포함된 모든 Bean을 스캔하는 @SpringBootTest과 비교하면 실행 속도가 훨씬 빠르다.
- @Entity로 선언된 JPA 엔티티
@DataJpaTest는 기본적으로 @Entity 클래스를 스캔해서 ApplicationContext에 로드한다. @Component로 등록된 Bean은 로드되지 않는다. @Service, @Repository, @RestController, @Configuration 등 내부적으로 @Component가 포함된 클래스들은 Bean으로 등록되지 않는다.
따라서 해당 객체를 @Autowired로 주입하려고 하면 에러가 발생한다.
- EntityManager, TestEntityManager
@DataJpaTest를 사용하면 표준 JPA EntityManager와 Spring Boot에서 제공하는 TestEntityManager가 Application Context에 자동으로 등록된다.
위 auto-configuration 클래스 목록 중에
org. springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration를 통해 TestEntityManager가,
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration를 통해 표준 JPA EntityManager가 등록된다.
TestEntityManager은 테스트만을 위해 사용되는 Bean이며, 내부적으로 EntityManager을 사용하고 있는 Wrapper 클래스이다. EntityManager의 모든 기능 + 테스트를 위한 추가적인 유틸리티 메서드를 제공한다. persistFlushFind()로 한 번에 persist, flush, find를 수행할 수 있고 flush를 자동으로 처리할 수 있어서 유용하다. TestEntityManager을 @DataJpaTest 범위 밖에서도 사용하고싶으면 @AutoConfigureTestEntityManager을 사용하면 된다.
@DataJpaTest
class ExampleRepositoryTests {
@Autowired
private TestEntityManager entityManager; //TestEntityManager가 주입됨
}
@DataJpaTest
class QueryDslEventRepositoryTest {
@Autowired
private EntityManager em; //표준 JPA EntityManager가 주입됨
}
3. 테스트가 끝날 때마다 Rollback
@DataJpaTest는 기본적으로 @Transactional을 포함하기 때문에 각 테스트가 끝나면 rollback된다.
테스트가 끝난 후 rollback하지 않고 commit하고싶으면 @Rollback(false)로 설정해주면 된다.
@DataJpaTest
@Rollback(false)
class ExampleNonTransactionalTests {
}
JPA의 EntityManager은 트랜잭션이 시작하면 그 때부터 엔티티의 변경사항을 추적하여 쿼리를 생성하고, 트랜잭션이 끝나면 flush, commit하여 변경된 엔티티들이 데이터베이스에 반영된다. 따라서 JPA를 사용한다면 테스트 시 반드시 트랜잭션 안에서 실행되어야 한다.
* reference