티스토리 뷰
🤔 Repository 테스트시 auto_increment의 id 컬럼 의존성을 끊을수는 없을까?
junojuno 2024. 1. 30. 21:47문제 상황
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
'Programming > Database' 카테고리의 다른 글
📻 SQL 성능 튜닝 - (2) 실행계획을 분석해 성능 튜닝을 해보자! (1) | 2024.01.31 |
---|---|
📻 SQL 성능 튜닝 - (1) 왜 SQL 튜닝을 해야하지? 어떻게 하지? (1) | 2024.01.31 |
DDL, DML, DCL (0) | 2023.03.20 |
Database session이란? 그리고 MySQL에서의 thread (0) | 2023.03.02 |
원티드 프리온보딩 백엔드 챌린지 - 데이터베이스 1일차 (0) | 2023.02.09 |
- Total
- Today
- Yesterday