Mockito를 이용한 단위 테스트 코드 작성 중에 아래와 같은 예외가 발생했다.
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
- stubbing the same method multiple times using 'given().will()' or 'when().then()' API
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
- stubbed method is intentionally invoked with different arguments by code under test
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
예외 메시지 대로 기존에 사용했던 given() when() 대신 doReturn() when()을 사용했다.
1) 둘 다 똑같이 mock object의 메서드를 호출하며 spy를 사용할 때 차이점이 있다.
출처
2) given().will(), when().then() 은 StrictMode, will().given(), doReturn().when()은 Lenient Mode로 동작한다.
출처
3) when() thenReturn(), given() willReturn() 차이점
그럼 when() thenReturn() 과 given() willReturn()은 뭐가 다른 것일까?
when() thenReturn() 은 org.mockito.Mockito를 import하고, given() willReturn()은 org.mockito.BDDMockito를 import 한다.
BDD는 Behavior-Driven-Development의 약자로 행위 주도 개발을 뜻한다.
시나리오를 기반으로 테스트하는 패턴을 권장하며 권장하는 기본 패턴은 Given(테스트 대상의 상태), When(상태의 변화를 가했을 때), Then(기대하는 상태) 구조이다.
given-when-then의 구조를 코드에 적용했을 때
//given 부분에 when이 나오게 되다 보니 맞지 않는 부분이 있게 되고 이를 해결하기 위해 나온 것이 BDDMockito이다.
즉 BDDMockito는 BDD를 사용하여 테스트 코드를 작성할 때 도움을 주는 프레임워크인 것이다.
출처
Mockito stubbing에서 디폴트는 strict stubbing이다.
strict stubbing은 같은 메서드에 대해 여러 번 when을
호출할 경우 Test Fail로 처리한다. 해결 방법은 when을 한 번만 호출하던가, 아니면 lenient stubbing을 사용하는 것이다.
@MockitoSettings(strictness = Strictness.LENIENT)
하지만 lenient stubbing을 사용할 경우 느슨한 stubbing을 제공하여 의도하지 않은 버그를 찾아내기가 쉽지 않다.
그래서 lenient stubbing을 locally 하게 사용하는 것으로 바꾸었다.
@Test
void refreshToken_쿠키없음() throws Exception{
//given
lenient().when(refreshTokenService.findByToken(null))
.thenReturn(null);
//when
ResultActions ra = mvc.perform(
get("/refreshToken")
.cookie(new Cookie("refreshToken", "test")));
//then
MvcResult mvcResult = ra.andExpect(status().isUnauthorized()).andReturn();
Assertions.assertThat(mvcResult.getResponse().getContentAsString()).isEmpty();
}