Mockito를 사용하여 Service단 테스트 코드를 작성 중 doReturn(…).when(…) 과 when().thenReturn() 구문이 동일하게 동작하는 것으로 보여 무슨 차이가 있는지 찾아보았다.
//순서만 다를 뿐 동작은 같다.
//when().thenReturn()
when(projectRepository.findById(any(Long.class))).thenReturn(Optional.empty());
//doReturn().when()
doReturn(Optional.empty()).when(projectRepository.findById(any(Long.class)));
결론부터 얘기하자면 when().thenReturn()을 사용하는 것이 권장된다고 한다.
//Mockito javadoc 인용
Use doReturn() in those rare occasions when you cannot use when(Object). Beware that when(Object) is always recommended for stubbing because it is argument type-safe and more readable (especially when stubbing consecutive calls).
우선 사람들은 대부분 왼쪽에서 오른쪽으로 글을 읽는데, when().thenReturn() 의 경우 사람이 읽는 순서와 동일하게 코드가 작성되어 읽기가 편하지만 doReturn의 경우 반대로 해석해야 하므로 가독성이 저하된다.
그러나 when 대신 doReturn을 사용해야 하는 드문 경우가 있다.
doReturn을 사용하는 경우
실제 객체를 spy 객체로 사용하고 실제 메서드를 호출하는 경우
List list = new LinkedList();
List spy = spy(list);
//Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");
//You have to use doReturn() for stubbing:
doReturn("foo").when(spy).get(0);
when을 사용하면 spying 중인 list 객체에서 실제로 get(0) 메서드를 호출하여 IndexOutOfBoundsException이 발생한다.
이런 경우 doReturn을 사용하면 실제 메서드를 호출하지 않고 테스트를 수행할 수 있다.
이전 예외 스텁 재정의
when(mock.foo()).thenThrow(new RuntimeException());
//Impossible: the exception-stubbed foo() method is called so RuntimeException is thrown.
when(mock.foo()).thenReturn("bar");
//You have to use doReturn() for stubbing:
doReturn("bar").when(mock).foo();
위의 코드는 mock.foo()가 RuntimeException을 throw하도록 정의했다가 “bar”를 반환하도록 재정의하도록 작성되어 있다.
그러나 when을 사용할 경우 mock.foo를 호출하면서 위에서 정의한 예외가 throw 되므로 thenReturn은 작동하지 않는다.
이런 경우 doReturn을 사용하면 when으로 만든 예외 스텁을 무시하고 “bar”라는 리턴 값을 얻을 수 있다.
그러나 위와 같은 시나리오는 매우 드물다. 일반적으로 스텁을 재정의 하는 것은 한 테스트 코드에 너무 많은 일을 하게 하는 잠재적인 코드 스멜의 원인이 된다.
참고
https://stackoverflow.com/questions/20353846/mockito-difference-between-doreturn-and-when
'JAVA' 카테고리의 다른 글
[이펙티브 자바] Item 10. equals는 일반 규약을 지켜 재정의하라 (1) | 2023.01.25 |
---|---|
[Java] equals와 hashCode (0) | 2022.12.22 |
[Java] Stream API 정리 (0) | 2022.11.27 |
Java Optional(옵셔널) (0) | 2022.11.23 |
[JAVA] Reflection (리플렉션)이란? (0) | 2022.11.17 |