데이터베이스

[DB / 테스트] @DataJpaTest

syj0522 2024. 11. 26. 12:27

@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으로 등록되지 않는다.

@Repository에 내부적으로 포함된 @Component 어노테이션

따라서 해당 객체를 @Autowired로 주입하려고 하면 에러가 발생한다.

QueryDslEventRepository는 @Repository에 해당하는 클래스이므로 @DataJpaTest로 의존 주입 불가, 에러 발생

- 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

출처:spring-boot 공식문서