본문 바로가기
잡다구리

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
    }

}

댓글