오늘 단위테스트를 작성하던 도중 TaxInvoiceReserveItemRepository(@SpyBean) 을 설정하던 중 any() 파라미터를 사용했는데 다음과 같은 예외를 발생해서 원인에 대해 확인해보려고 합니다.
// InvalidUseOfMatchersException 예외 발생
// Invalid use of argument matchers!, 3 matchers expected, 1 recorded
when(taxInvoiceReserveItemRepository.findItemsByOrderNoWithLock(
tiReserve.getSalesOrderNo(),
anyList(),
DocType.ORDER))
.thenReturn(tiReserve.getItems());
ArgumentMatchers
메소드 기능에 대한 테스트를 진행할 때 고정된 인자 값으로 테스트를 진행하는 경우도 있겠지만 메서드 안정성을 위해 다양한 값의 인자로 테스트를 진행해야 합니다. ArgumentMatchers 클래스는 메소드 파라미터를 다양한 인자 값으로 설정하여 실행할 때 메소드가 정상적으로 수행되는지 확인할 수 있는 도구입니다. mockito 5.3.1 버전을 기준으로 any(), anyList(), anyString(), anyLong() 등 다양한 메서드를 지원하고 있습니다.
에러의 원인은 무엇일까?
ArgumentMatchers가 무엇인지는 대충 알았고 위와 같은 에러가 발생하는 원인은 무엇일까? 메소드 인자 중 하나라도 ArgumentMatchers 를 사용한다면 모든 인자에 대해 ArgumentMatchers를 사용해야 한다고 합니다. 그래서 값을 고정해서 메소드를 실행해야 하기 때문에 eq 를 사용하여 아래와 같이 테스트 했는데 또 다른 예외가 발생했습니다..
// 예외!! eq(null) is not allowed, Use isNull() instead
when(taxInvoiceReserveItemRepository.findItemsByOrderNoWithLock(
eq(tiReserve.getSalesOrderNo()),
anyList(),
eq(DocType.ORDER))) // NULL로 실행됨!
.thenReturn(tiReserve.getItems());
추적해보니 findItemsByOrderNoWithLock 메서드를 Querydsl로 JPQL을 생성하고 있는데 조건 절에서 DocType이 null로 넘어가는 것이 문제였다. eq를 통해 값을 지정했는데 왜 null로 넘어가는 것일까..
문제의 원인을 찾아봤는데 eq메서드 안의 defaultValue 메서드를 보니 PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES 맵에는 커스텀한 사용자의 Enum 클래스에 대한 설정이 저장되어 있지 않기 때문인 것 같다.
public static <T> T eq(T value) {
reportMatcher(new Equals(value));
return value == null ? null : Primitives.defaultValue(value.getClass());
}
public static <T> T defaultValue(Class<T> primitiveOrWrapperType) {
return PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES.get(primitiveOrWrapperType);
}
그래서 아래와 같이 any(DocType.class)로 변경해보았는데 역시 PRIMITIVE_OR_WRAPPER_DEFAULT_VALUES에 Enum 타입이 없어서 null을 리턴하게 되면서 정상적인 테스트 확인에 실패했습니다.
when(taxInvoiceReserveItemRepository.findItemsByOrderNoWithLock(
eq(tiReserve.getSalesOrderNo()),
anyList(),
any(DocType.class))).thenReturn(tiReserve.getItems());
구글링을 해봤는데 깔끔한 해결 방법이 보이지 않는다.. 이런 문제는 분명 많이 발생할 것 같은데 말이지.. 리스트 설정하기 귀찮아서 anyList() 를 사용하며 발생한 문제인데 우선은 ArgumentMatchers를 빼고 테스트를 진행해야겠다.. 다음에 또 만나면 그때는 해결하도록 해봐야지..
'TIL(Today I Learned)' 카테고리의 다른 글
[Today I Learned - 6] Springboot에서 Logback 설정하기 (0) | 2024.01.09 |
---|---|
[Today I Learned - 5] @Transactional의 readOnly 속성 (0) | 2024.01.08 |
[Today I Learned - 3] @Nonnull(jakarta.annotation) 과 @NotNull(jakarta.validation.constraints) (0) | 2023.12.22 |
[Today I Learned - 2] MySQL 서버 연결 차이점 (0) | 2023.12.14 |
[Today I Learned - 1] unable to find valid certification path to requested target (0) | 2023.07.10 |