티스토리 뷰

문제 상황

Entity에서 key 생성 전략을 IDENTITY로 설정하면 auto_increment로 id가 null로 설정되어 DB에 INSERT이후, DBMS를 통해서 id 값을 받아 온다.

그런데, 이 auto_increment에 의존해 테스트를 위와 같이 작성할 경우,

각 테스트 마다 1부터 다시 id값을 생성하는게 아닌, 연속해서 id를 발행하기 때문에, auto_increment로 생성된 id에 의존해 테스트하는것에 문제가 생겼다.

 

아래 코드에서 보면, Template에는 id와 해당 template html을 저장한다. (아래는 template에 임의로 template 1,2를 넣어둔 것이다)

그래서 각 MailHistory는 어떤 template으로 보낼지 template이름을 가지고 있는데, tempate이름이 WELCOME이면 template id가 1, EVENT_STATUS_CHANGED이면 2로 설정된다.

@SpringBootTest
@Transactional
class TemplateNameRepositoryTest {

    @Autowired
    private TemplateRepository templateRepository;
    @Autowired
    private MailTrackerRepository mailTrackerRepository;

    @BeforeEach
    void setUp() {
        Template template1 = Template.builder()
                .template("template 1")
                .build();
        Template template2 = Template.builder()
                .template("template 2")
                .build();
        templateRepository.saveAll(List.of(template1, template2));

        MailHistory mailHistory1 = MailHistory.builder()
                .addresses("abcd@naver.com")
                .title("title 1")
                .templateName(TemplateName.WELCOME)
                .sentAt(LocalDateTime.now())
                .isSent(true)
                .build();
        MailHistory mailHistory2 = MailHistory.builder()
                .addresses("zxcv@naver.com")
                .title("title 2")
                .templateName(TemplateName.EVENT_STATUS_CHANGED)
                .sentAt(LocalDateTime.now())
                .isSent(true)
                .build();
        MailHistory mailHistory3 = MailHistory.builder()
                .addresses("asdf@naver.com")
                .title("title 1")
                .templateName(TemplateName.WELCOME)
                .sentAt(LocalDateTime.now())
                .isSent(false)
                .build();

        mailTrackerRepository.saveAll(List.of(mailHistory1, mailHistory2, mailHistory3));
    }

    @ParameterizedTest
    @CsvSource({"EVENT_STATUS_CHANGED,template 2", "WELCOME,template 1"})
    void findByTemplateName(TemplateName templateName, String expectedTemplate) {
        // when
        String actualTemplate = templateRepository.findTemplateByTemplateName(templateName);

        // then
        assertThat(actualTemplate).isEqualTo(expectedTemplate);
    }

}

 

이렇게 WELCOME 템플릿은 id가 1, EVENT_STATUS_CHANGED는 id가 2로 고정되어 있다.

이럴때 위 repository 테스트를 실행시키면 테스트가 깨지는데, 이유는 한 application context에서 auto_increment값은 순차적으로 증가된다. 따라서 하나의 application context를 공유하고 있으면, 첫 테스트에서 id값을 1,2로 생성되면 그 다음번에는 3,4의 id값이 생성된다.

 

이 문제를 어떻게 해결 할 수 있을까?

해결방법 1️⃣

@DirtiesContext를 사용해 아래와 같이 매 테스트 메서드 실행 이후 Application Context를 새로 만들어 주는 방법을 사용했다.

이 방법을 사용하면 매 테스트마다 application context를 재생성하여 auto_increment값이 1로 초기화된다.

하지만 이 방법은 테스트간 격리가 가능하지만, Application Context가 재생성되기에 테스트 성능 저하를 초래할 수 있다.
그래서 테스트 속도가 매우 느렸다! 

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)

로컬환경에서 실행했을 때 360ms가 두개의 테스트를 실행하는데 소요되었다.]

 

해결방법 2️⃣

데이터베이스에 native query를 통해 auto increment 시작 숫자를 재설정 하여 문제를 해결하였다.

tearDown 메서드를 통해 아래 메서드를 실행시켜줌으로서 테스트가 id값에 의존할 때 auto_increment와 테스트 순서간의 연관관계를 끊을 수 있었다.

    @Autowired
    private EntityManager entityManager;

    @AfterEach
    void resetAutoIncrementId() {
        entityManager.createNativeQuery("ALTER TABLE TEMPLATE ALTER COLUMN template_id RESTART WITH 1")
                .executeUpdate();
    }

이렇게 한다면 매번 application context를 재생성할 필요가 없어 실행 시간 또한 @DirtiesContext 를 사용하는 시간보다 빠르다.

로컬환경에서 실행했을 때 360ms → 345ms로 테스트 소요시간이 준 것을 확인할 수 있었다.

 

Reference

https://github.com/HomoEfficio/dev-tips/blob/master/Spring%20Data%20JPA%20%ED%85%8C%EC%8A%A4%ED%8A%B8%20%EC%8B%9C%20auto-increment%20%EB%AC%B8%EC%A0%9C.md

 
미국∙영국
[ˈrefrəns]
1. (… 에 대해) 말하기, 언급; 언급 대상, 언급한 것
2. (정보를 얻기 위해) 찾아봄, 참고, 참조
3. 참고[참조] 표시를 하다, 참조 문헌(목록)을 달다
 
 
 
 
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday