2023. 12. 20. 13:37ㆍProject 해축갤/테스트 코드
배경
@Transactional
@Scheduled(cron = "0 0 * * * *")
public void updatePopularPosts() {
// 새로운 상위 10개 게시물 추출
List<Tuple> top10Posts = postRepository.findTop10Posts();
// 기존의 data 삭제
popularPostRepository.deleteAllInBatch();
// 변환 후 새로운 data 삽입
List<PopularPost> popularPosts = convertToPopularPost(top10Posts);
popularPostRepository.saveAll(popularPosts);
}
위 함수에 대한 테스트 코드를 작성해보려 하다 이런 글을 쓰게 되었습니다.
테스트의 목적은 매 정시에 함수가 실제로 호출되는지 여부를 확인하는 것이었습니다.
찾아본 솔루션 2가지
- 통합 테스트
- Awaitiliy
두 가지 방법 모두 코드 구현에는 차이가 있지만, 궁극적으로는 짧은 시간 간격으로 스케줄링된 함수의 호출 여부를 확인하는 방식입니다.
이는 짧은 주기로 스케줄링된 함수에 대해 효과적인 테스트 방법입니다.
그러나 문제는, 제 함수는 매 정시마다 스케줄링되어 있어서, 테스트를 위해 매시간 기다릴 수는 없는 상황입니다. 따라서, 직접적인 함수 호출을 확인하는 대신, @cron 표현식이 제대로 적용되어 매 정시마다 함수를 트리거하는지 여부에 초점을 맞추어 문제를 다시 접근하게 되었습니다.
@cron 표현식 테스트
이 접근 방식은 @Scheduled 어노테이션에 설정된 cron 표현식이 올바르게 구성되어
실행 시간을 정확히 계산하는지 검증하는 데 중점을 둡니다.
실제 함수 호출이 아닌, 예정된 호출 시간이 정확한지 확인함으로써 스케줄링 로직의 정확성을 검증하는 방식입니다.
테스트 구현 방법
- Cron 표현식 파싱: 먼저, @Scheduled 어노테이션에 정의된 cron 표현식을 파싱합니다. 이는 스케줄링의 시간 기준을 설정하는 데 사용됩니다.
- 예상 실행 시간 계산: 특정 기준 시간(예: 현재 시간)으로부터 cron 표현식에 따라 다음 실행 시간을 계산합니다.
- 검증: 계산된 실행 시간이 실제로 cron 표현식에 의해 예상되는 시간과 일치하는지 확인합니다. 이를 통해 스케줄러가 정확히 매 정시마다 함수를 호출하도록 설정되었는지 검증할 수 있습니다.
예상 결과
이 테스트를 통해 updatePopularPosts 메서드가 매 정시마다 올바르게 트리거되는지 확인할 수 있습니다. 실제 시간을 기다리지 않고도 스케줄링 로직의 정확성을 효과적으로 검증하는 방법으로, 특히 크론 표현식의 복잡성을 고려할 때 매우 유용합니다.
구체적인 테스트 코드 예시
class PopularPostServiceTest {
@Test
@DisplayName("updatePopularPosts 메서드가 매시 정각에 실행되어야 한다")
public void shouldTrigger_updatePopularPosts_atEveryHour() throws ParseException {
// Given - 상황 설정
// 매시 정각을 의미하는 cron 표현식 설정
String cronExpression = "0 0 * * * *";
// Cron 트리거 생성: 주어진 cron 표현식으로 다음 실행 시간을 계산할 객체
CronTrigger trigger = new CronTrigger(cronExpression);
// 테스트 시작 시간을 설정함
Date startTime = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse("2023/12/20 00:00:00");
// 스케줄링 컨텍스트 초기화
SimpleTriggerContext context = new SimpleTriggerContext();
context.update(startTime, startTime, startTime);
// 예상되는 실행 시간 목록
List<String> expectedTimes = Arrays.asList(
"2023/12/20 01:00:00",
"2023/12/20 02:00:00",
"2023/12/20 03:00:00");
// When - 동작 수행
// 각 예상 시간에 대해 cron 표현식에 따라 계산된 다음 실행 시간을 검증
for (String expectedTime : expectedTimes) {
Date nextExecutionTime = trigger.nextExecutionTime(context);
// Then - 결과 검증
// 계산된 실행 시간이 예상 시간과 일치하는지 확인
String actualTime = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(nextExecutionTime);
assertThat(actualTime, is(expectedTime));
// 다음 예상 시간 계산을 위해 컨텍스트 업데이트
context.update(nextExecutionTime, nextExecutionTime, nextExecutionTime);
}
}
}
이 코드는 @Scheduled 어노테이션에 설정된 cron 표현식이 올바르게 작동하는지 확인하는 테스트를 수행합니다.
주어진 cron 표현식에 따라 예상되는 실행 시간을 계산하고, 이를 실제로 예상된 시간과 비교하여 검증합니다.
결론
이번 글에서 @Scheduled 어노테이션의 cron 표현식이 제대로 설정되었는지 간단히 확인할 수 있었습니다.
이 방식은 실제 함수의 실행을 기다리지 않고도, 예정된 시간에 맞춰 함수가 트리거되는지를
빠르게 검증할 수 있는 효과적인 방법입니다.
이러한 접근 방식을 사용하면, 크론 스케줄링 로직이 정확하게 작동하는지를 효율적으로 확인할 수 있어,
개발 과정에서 시간을 절약하고 신뢰성을 높일 수 있습니다.
참고
How to Test the @Scheduled Annotation | Baeldung
Spring의 @Scheduled annotation으로 설정된 cron expression을 테스트하기 - 개발수양록
'Project 해축갤 > 테스트 코드' 카테고리의 다른 글
JUnit5 테스트 메서드는 왜 public 이면 안될까? (2) | 2024.01.08 |
---|---|
테스트 띠띠ㅣ디ㅣ디ㅣ딛ㄹ딸깍? postman 으로 '띡띡딸깍' 하기 (1) | 2023.11.30 |
Hibernate의 "Detached Entity Passed to Persist" 오류 이해와 해결 (0) | 2023.11.08 |
org.mockito.exceptions.misusing.UnnecessaryStubbingException 해결 (0) | 2023.11.07 |
테스트를 더 빨리 끝내보기 (feat. 자료구조, singletonList) (0) | 2023.11.02 |