Mockito : doAnswer 대 thenReturn


124

나중에 서비스 단위 테스트를 위해 Mockito를 사용하고 있습니다. 언제 doAnswerthenReturn.

누구든지 나를 자세히 도울 수 있습니까? 지금까지 thenReturn.

답변:


167

메서드 호출을 모의 할 때 thenReturn또는 doReturn반환 값을 알고있는 경우를 사용해야합니다 . 이 정의 된 값은 모의 메서드를 호출 할 때 반환됩니다.

thenReturn(T value) 메서드가 호출 될 때 반환 될 반환 값을 설정합니다.

@Test
public void test_return() throws Exception {
    Dummy dummy = mock(Dummy.class);
    int returnValue = 5;

    // choose your preferred way
    when(dummy.stringLength("dummy")).thenReturn(returnValue);
    doReturn(returnValue).when(dummy).stringLength("dummy");
}

Answer 모의 메서드가 호출 될 때 추가 작업을 수행해야하는 경우 (예 :이 메서드 호출의 매개 변수를 기반으로 반환 값을 계산해야 할 때) 사용됩니다.

doAnswer()generic으로 void 메서드를 스텁하려는 경우 사용 합니다 Answer.

응답은 실행되는 작업과 모의 객체와 상호 작용할 때 반환되는 반환 값을 지정합니다.

@Test
public void test_answer() throws Exception {
    Dummy dummy = mock(Dummy.class);
    Answer<Integer> answer = new Answer<Integer>() {
        public Integer answer(InvocationOnMock invocation) throws Throwable {
            String string = invocation.getArgumentAt(0, String.class);
            return string.length() * 2;
        }
    };

    // choose your preferred way
    when(dummy.stringLength("dummy")).thenAnswer(answer);
    doAnswer(answer).when(dummy).stringLength("dummy");
}

안녕하세요 @Roland Weisleder은 그러나 때때로 당신은 예를 들어 내부 코드 및 인수와는 아무 생성 어떤 값을 반환해야합니다 code = UUID.randomUUID(), 나는 이것을 구현하는 것은 불가능 발견 mockito.
zhuguowei

3
당신의 모의 각 호출에 대해 새 UUID를 반환해야 할 때 당신은을 구현하는 것이 Answer단지와 함께 return UUID.randomUUID();.
Roland Weisleder 2016 년

코드를 좀 더 깔끔하게 만들기 위해 새로운 Answer 초기화 개미에서이 방법을 사용할 수 있습니까?
Line

3
@Line Answer은 기능적 인터페이스이므로 Java 8에서는이를 람다 식으로 바꿀 수 있습니다. 깨끗하지 않으면 다른 평범하고 비정상적인 리팩토링이 가능합니다.
Roland Weisleder 2017 년

@ zhuguowei : 일부 값 생성 내부 코드를 반환합니까? 그게 무슨 뜻 이니?
Saurabh Patil 2018

34

doAnswer다음과 thenReturn같은 경우 동일한 작업을 수행합니다.

  1. Spy가 아닌 Mock을 사용하고 있습니다.
  2. 스터 빙하는 메서드는 void 메서드가 아닌 값을 반환합니다.

이 BookService를 모의 해 보겠습니다.

public interface BookService {
    String getAuthor();
    void queryBookTitle(BookServiceCallback callback);
}

doAnswer및을 사용하여 getAuthor ()를 스텁 할 수 있습니다 thenReturn.

BookService service = mock(BookService.class);
when(service.getAuthor()).thenReturn("Joshua");
// or..
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        return "Joshua";
    }
}).when(service).getAuthor();

사용할 때 참고 doAnswer, 당신의 메소드를 전달할 수 없습니다 when.

// Will throw UnfinishedStubbingException
doAnswer(invocation -> "Joshua").when(service.getAuthor());

따라서 doAnswer대신 언제 사용 thenReturn합니까? 두 가지 사용 사례를 생각할 수 있습니다.

  1. void 메서드를 "스텁"하고 싶을 때.

doAnswer를 사용하면 메서드 호출시 몇 가지 추가 작업을 수행 할 수 있습니다. 예를 들어 queryBookTitle에서 콜백을 트리거합니다.

BookServiceCallback callback = new BookServiceCallback() {
    @Override
    public void onSuccess(String bookTitle) {
        assertEquals("Effective Java", bookTitle);
    }
};
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        BookServiceCallback callback = (BookServiceCallback) invocation.getArguments()[0];
        callback.onSuccess("Effective Java");
        // return null because queryBookTitle is void
        return null;
    }
}).when(service).queryBookTitle(callback);
service.queryBookTitle(callback);
  1. Mock 대신 Spy를 사용하는 경우

when-thenReturn on Spy Mockito를 사용하면 실제 메서드를 호출 한 다음 답변을 스텁합니다. 이 샘플과 같이 실제 메서드를 호출하지 않으려면 문제가 발생할 수 있습니다.

List list = new LinkedList();
List spy = spy(list);
// Will throw java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
when(spy.get(0)).thenReturn("java");
assertEquals("java", spy.get(0));

doAnswer를 사용하면 안전하게 스텁 할 수 있습니다.

List list = new LinkedList();
List spy = spy(list);
doAnswer(invocation -> "java").when(spy).get(0);
assertEquals("java", spy.get(0));

실제로 메서드 호출시 추가 작업을 수행하지 않으려면 doReturn.

List list = new LinkedList();
List spy = spy(list);
doReturn("java").when(spy).get(0);
assertEquals("java", spy.get(0));

mocked 메서드가 무효이면 어떨까요?
Igor Donin

1
Igor, 그것이 바로 doAnswer ()가 그림으로 나오는 곳이며 위의 답변에서 그것을 다루었습니다.
Saurabh Patil 2018

사용할 때 doAnswer(new Answer() { ... return null;}eclipse에서 "Answer는 원시 유형입니다. 제네릭 유형 Answer <T>에 대한 참조는 매개 변수화되어야합니다"에 대한 경고가 표시됩니다. 이 문제를 해결할 수있는 방법이 있습니까 (경고 ofc 무시 제외)?
LazR
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.