본문 바로가기
잡다구리

Spring: @DataJpaTest

by Growing! 2022. 8. 14.

목차

    • JPA 컴포넌트의 테스트에만 포커스하는 애너테이션이다.

    • auto-configuration을 비활성화시키며, JPA 테스트에 필요한 configuration만 적용된다.

    • 각 테스트는 트랜잭션이 적용되어 실행되며, 테스트가 끝나면 롤백된다.

    • 기본적으로 인메모리 데이터베이스가 사용되기 때문에 @AutoConfigureTestDatabase(replace = Replace.NONE) 으로 오버라이드 해야 한다.

    • 실행되는 SQL의 로깅은 spring.jpa.show-sql 설정에 따르지만, 설정이 없으면 true 가 기본값이다.

    • @ActiveProfiles 로 테스트 환경을 명시하자. application-{테스트}.yml 도 준비하자.

      • 예) "springtest"
    • @ContextConfiguration 를 사용하여 ApplicationContext 를 로딩할 컴포넌트를 명시하자.

      • 해당 컴포넌트는 @SpringBootApplication 이 적용되어 있어야 하며, 해당 위치의 하위 패키지를 컴포넌트 스캔하게 되므로 반드시 최상위 패키지에 정의되어야 한다.
    • Repository에서는 다른 bean에 대한 의존성을 가지지 않도록 주의하자.

    • properties 속성으로 프로퍼티를 지정할 수 있다.

      • properties: String[] attribute에 [key=value, key=value, ...] 형식으로 지정한다.
    • Flyway를 사용하는 경우, auto configuration에서 제외해 주어야 한다.

      • @DataJpaTest(..., excludeAutoConfiguration = { FlywayAutoConfiguration.class })
    • (optional?) EnableJpaRepository 가 설정되어 있어야 한다(아래 예제에서는 없어도 잘 동작함).

    • @EnableJpaRepositories(basePackageClasses = { DemoDomain.class} )

    • (optional?) EnableEntityScan 을 설정한다(아래 예제에서는 없어도 잘 동작함). entity class를 스캔할 수 있는 위치를 지정해준다.

      • @EntityScan(basePackageClasses = { DemoDomain.class} )

      • 다음과 같은 오류가 발생하면 지정해 주어야 한다.

        • IllegalArgumentException: Not a managed type: entity class 이름

    spock 예시

    # source 패키지 구조
    my
    └── study
        └── buckpal
            └── domain
                ├── board
                │   └── ...
                └── user
                    ├── User.java
                    └── UserRepository.java
    
    # integration test 패키지 구조
    my
    └── study
        └── buckpal
            ├── JpaTestSupport.groovy
            ├── TestApplicationContextLoader.groovy
            └── domain
                └── UserJpaTest.groovy
    

    TestApplicationContextLoader.groovy

    // DataJpaTest 에서 필요한 ApplicationContext를 로드합니다.
    @SpringBootApplication
    class TestApplicationContextLoader {}
    
    • 이 클래스의 위치를 기준으로 컴포넌트 스캔을 수행하므로, 반드시 컴포넌트 스캔할 최상위 패키지에 존재해야 합니다. 그렇지 않으면 별도로 스캔 경로를 지정해주어야 합니다.

    JpaTestSupport.groovy

    // Spring DataJpaTest의 기본 설정들을 포함하는 상위 클래스
    @DataJpaTest
    @ContextConfiguration(classes = [TestApplicationContextLoader])
    @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
    @ActiveProfiles("springtest")
    @RunWith(SpringRunner.class)
    abstract class JpaTestSupport extends Specification {} 
    • ContextConfiguration - DataJpaTest 는 ApplicationContext를 로드하는 컴포넌트가 필요합니다.

    • Replace.NONE - application yml에 설정된 database를 사용합니다. 지정하지 않으면 In-Memory Database가 사용됩니다.

    • ActiveProfiles("springtest") - application-springtest.yml을 사용합니다.

    • RunWith(SpringRunner.class) - Spring TestContext의 기능을 제공해줍니다.

    UserRepositoryTest.groovy

    import my.study.buckpal.JpaTestSupport
    import my.study.buckpal.domain.user.User
    import my.study.buckpal.domain.user.UserRepository
    import org.springframework.beans.factory.annotation.Autowired
    
    import java.time.LocalDateTime
    
    class UserRepositoryTest extends JpaTestSupport {
    
        private final String email = "test@gmail.com";
    
        @Autowired
        UserRepository userRepository
    
        void setup() {
            User user = userRepository.save(User.builder()
                    .name("홍길동")
                    .password("패스워드")
                    .email(email)
                    .createdDate(LocalDateTime.now())
                    .build()
            )
        }
    
        def "user가 제대로 생성되었다"() {
            when:
            User user = userRepository.findByEmail(email)
    
            then:
            user.name == "홍길동"
            user.password == "패스워드"
            user.email == email
        }
    
    }
    

    댓글