테스트를 진행할 때 곤란한 상황 중 하나는 일정 시간이 지난 후 결과값이 달라지는 것입니다. 물론 우리는 시간의 변화에 따라 실패할 가능성이 있는 테스트를 작성해서는 안 됩니다.
그렇지만 테스트 대상 메서드 실행 시점으로부터 단 1초라도 지났을 때의 반환값과 현재의 반환값이 다름을 검증하고 싶을 때는 어떻게 해야할까요? 가장 먼저 생각나는 방법은 Tread.sleep()
을 호출하는 것입니다. 쉽고 간단한 방법이지만 전체 테스트 수행 시간도 덩달아 늘어난다는 문제점이 발생합니다.
이번 게시글에서는 이러한 상황에 유용하게 사용할 수 있는 테스트용 라이브러리 awaitility를 직접 사용해보고 정리해보았습니다.
awaitility는 비동기 시스템을 테스트할 때 사용할 수 있는 라이브러리입니다. 비동기 메서드를 실행했을 때, 해당 메서드의 반환값을 받기 위해서는 일정 시간 대기할 필요가 있습니다. 다음 예시를 한 번 살펴보겠습니다.
@Test
void updatesCustomerStatus() {
// 고객의 상태 변화에 관한 비동기 메시지를 발행한다.
messageBroker.publishMessage(updateCustomerStatusMessage);
// 고객의 상태 변화가 변경되었음을 확인하는 메서드가 실행될때까지 최대 5초 기다린다.
await().atMost(5, SECONDS).until(customerStatusIsUpdated());
...
}
//출처: <https://github.com/awaitility/awaitility>
이처럼 awaitility는 비동기적으로 발행되는 메시지가 있을 때, 해당 메시지를 소비하는 쪽의 상태가 변경될때까지 대기할 수 있도록 조절하는 방법을 제공합니다. 물론 이 과정에서 테스트 시간은 늘어나지 않습니다.
또한 .atLeast(5, SECONDS)
와 같이 시간의 변화에 따라 다른 반환값이 달라지는 상황에도
저는 리프레시 토큰
을 이용해서 액세스 토큰
을 갱신하는 상황을 테스트하고 싶었습니다.
@Test
@DisplayName("성공: 새로운 액세스 토큰이 발행됨")
void refreshAccessToken() {
//given
String refreshToken = memberToken.refreshToken();
//when
MemberToken newMemberToken = jJwtProvider.refreshAccessToken(refreshToken);
//then
assertThat(newMemberToken.accessToken()).isNotEqualTo(refreshToken);
}
문제는 테스트 수행시간이 너무 빠른 나머지 기존의 토큰과 동일한 값을 가진 액세스 토큰이 발행된다는 점이었습니다.
다행히 awaitility는 최소 이만큼 대기하라!
라고 메시지를 전달하는 .atLeast()
메서드를 제공합니다. 해당 메서드를 위 테스트 코드에 적용하면 다음과 같이 변경됩니다.
@Test
@DisplayName("성공: 새로운 액세스 토큰이 발행됨")
void refreshAccessToken() {
//given
String refreshToken = memberToken.refreshToken();
//when
//then
await().atLeast(10, TimeUnit.MILLISECONDS).untilAsserted(() ->
{
MemberToken newMemberToken = jJwtProvider.refreshAccessToken(refreshToken);
assertThat(newMemberToken.accessToken()).isNotEqualTo(refreshToken);
});
}