[Spring Boot] 테스트 환경 분리 및 Gradle 태스크 구성으로 Audit 문제 해결

janjanee·어제
0

Spring

목록 보기
3/3

배경

Spring Boot 애플리케이션의 테스트를 수행할 때, 단독 클래스에서는 모든 테스트가 성공하였다. 그러나 전체 테스트를 실행하면 동일한 테스트 컨텍스트를 공유하면서
JPA Audit 기능이 의도치 않게 적용되는 문제가 발생하였다.

DirtiesContext나 ActiveProfile 등으로 해결을 시도하려했으나 효과가 없었다.
그래서 테스트 컨텍스트 자체를 분리하기로 했다.

코드

@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntityAbstract implements Serializable {

    @Column(updatable = false, nullable = false)
    @CreatedDate
    private LocalDateTime createAt;

    @Column(nullable = false)
    @LastModifiedDate
    private LocalDateTime updateAt;
}
  • JPA Entity에 공통으로 @CreatedDate, @LastModifiedDate Audit 적용된 상태이다.
@DataJpaTest
class MessageRepositoryTest {

   @Test
   public void 생성일_특정조건으로_메시지_검색() {
       // given
       MessageSearchDto searchDto = 
       Instancio.of(MessageSearchDto.class)
           .set(field(MessageSearchDto::getStartAt), LocalDateTime.of(2025, 3, 20, 12, 0, 0))
           .set(field(MessageSearchDto::getEndAt), LocalDateTime.of(2025, 3, 21, 12, 0, 0))
           .create();

       // when
       PageRequest pageRequest = PageRequest.of(0, 10);
       Page<MessageDto> result = messageRepository.findAllBySearchCondition(pageRequest, searchDto);

       // then
       assertThat(result.getContent()).hasSize(1);
  }
}
  • 위 코드에는 적혀져있지 않지만, BeforeEach에서
    2025-03-20T15:00:00 인 Message 데이터를 하나 생성했다고 가정한다.
  • JPA 슬라이싱 테스트 클래스가 있고, 이 클래스만 단독으로 테스트 수행하면
    then절에서 예상하는 대로 1개의 메시지가 조회되어 테스트가 통과된다.

문제상황

그러나 모든 테스트를 전체 수행하면 @SpringBootTest 테스트의 컨텍스트
엮이면서 Audit이 적용되어 내가 BeforeEach에서 생성한
2025-03-20T15:00:00 날짜인 데이터가 테스트를 실행하는 시점의
시간으로 Insert
되어서, 위의 테스트 케이스가 실패했다.

해결

테스트 코드 패키지를 test/ 하위에 두 개의 최상위 패키지로 분리하였다.

test/java/com/hello/unit
test/java/com/hello/integration
  • unit: Spring Boot 전체 환경을 로드하지 않는 단위 테스트 코드 클래스
  • integration: 전체 Spring 환경을 로드하는 통합 테스트 코드 클래스

이와 같이 패키지 구조를 분리함으로써, 전체 테스트 실행 시 서로 다른 테스트 컨텍스트를 사용하여 의도치 않은 Audit 기능 적용 문제를 방지하였다.

그리고 아래 코드를 build.gradle에 적용한다.

tasks.register('integrationTest', Test) {
    useJUnitPlatform()
    include '**/integration/**'
}

test {
    useJUnitPlatform()
    include '**/unit/**'
    finalizedBy integrationTest
}

적용 후 ./gradlew build 를 실행해서 확인해보면
아래와 같이 test, integrationTest 2개의 task가 각각 별도로 실행되어
모든 테스트를 통과하는 것을 확인했다.

로컬 테스트 IDE 적용

  • IntelliJ를 사용하면 Run에 :check 로 변경하여
    위의 두개의 테스트가 모두 수행될 수 있도로 변경하거나 또는
    cli로 ./gradlew check or ./gradlew build를 수행해서
    로컬에서 테스트 수행이 가능하다.
profile
얍얍 개발 펀치

0개의 댓글

관련 채용 정보