동일한 인수로 동일한 메소드를 여러 번 호출하여 Mockito 사용


289

스텁 된 메소드가 후속 호출에서 다른 오브젝트를 리턴하도록하는 방법이 있습니까? 의 결정되지 않은 응답을 테스트하기 위해이 작업을 수행하고 싶습니다 ExecutorCompletionService. 즉, 방법의 반환 순서와 상관없이 결과를 일정하게 유지합니다.

테스트하려는 코드는 다음과 같습니다.

// Create an completion service so we can group these tasks together
ExecutorCompletionService<T> completionService =
        new ExecutorCompletionService<T>(service);

// Add all these tasks to the completion service
for (Callable<T> t : ts)
    completionService.submit(request);

// As an when each call finished, add it to the response set.
for (int i = 0; i < calls.size(); i ++) {
    try {
        T t = completionService.take().get();
        // do some stuff that I want to test
    } catch (...) { }        
}

답변:


254

thenAnswer메소드 를 사용하여 수행 할 수 있습니다 (와 체인을 연결할 때 when).

when(someMock.someMethod()).thenAnswer(new Answer() {
    private int count = 0;

    public Object answer(InvocationOnMock invocation) {
        if (count++ == 1)
            return 1;

        return 2;
    }
});

또는 동등한 정적 doAnswer방법을 사용하십시오 .

doAnswer(new Answer() {
    private int count = 0;

    public Object answer(InvocationOnMock invocation) {
        if (count++ == 1)
            return 1;

        return 2;
    }
}).when(someMock).someMethod();

635

어때요?

when( method-call ).thenReturn( value1, value2, value3 );

thenReturn의 괄호에 원하는만큼의 인수를 입력 할 수 있습니다 (모두 올바른 유형 인 경우). 첫 번째 값은 메소드가 처음 호출 될 때 리턴되고 두 번째 응답 등이 리턴됩니다. 다른 모든 값이 모두 사용되면 마지막 값이 반복해서 반환됩니다.


4
이것은 모의와 함께 작동하지만 스파이와는 작동하지 않습니다. 원래 메소드 호출을 막으려면 doAnswer (...). when (someSpy) .someMethod (...)가 필요합니다.
Yuri

6
@ Yuri-별로는 아닙니다. 언급 한 경우 doAnswer를 쓰거나 작성할 필요가 없습니다 Answer. 당신은 사용할 수 있습니다 doReturn(...).when(someSpy).someMethod(...). 엠마가 스파이보다는 모의에 관심이 있다고 가정하는 것이 합리적이지만, 나는 이것을 대답하기 위해 내 대답에 무언가를 추가 할 수 있다고 생각합니다. 의견 주셔서 감사합니다.
Dawood ibn Kareem

@DawoodibnKareem은 첫 번째 호출에 대해 값을 반환하고 두 번째 호출에 대해 예외를 throw하려고한다고 말할 수 있습니다. 어떻게 할 수 있습니까?
Rito

@Rito Volodymyr의 답변 또는 Raystorm의 답변을 읽으십시오. 그들은 모두 그 사건을 다룹니다.
Dawood ibn Kareem

영광스러운 답변입니다.
wild_nothing

151

앞에서 지적했듯이 거의 모든 통화는 연결 가능합니다.

그래서 당신은 전화 할 수

when(mock.method()).thenReturn(foo).thenReturn(bar).thenThrow(new Exception("test"));

//OR if you're mocking a void method and/or using spy instead of mock

doReturn(foo).doReturn(bar).doThrow(new Exception("Test").when(mock).method();

Mockito의 Documenation에 대한 자세한 정보 .


3
매우 도움이되었습니다! mock.method이 예에서 네 번째 시간 은 어떻게됩니까? 나는 foo를 처음으로 반환하지만 나머지는 모두 bar를 반환합니다.
javaPlease42

6
모의에 대한 각 추가 호출은 마지막 'thenReturn'또는 마지막 'thenThrow'를 반환합니다. 매우 유용합니다
Francois Lacoursiere

위대하고 간단한 지침에 감사드립니다. 지금까지 이것을 알지 못했습니다. 두 번의 동일한 호출에서 두 가지 다른 결과를 얻는 방법을 찾기 위해 고심하고있었습니다. 많은 시간을 절약하십시오.
CharlesC

68

doReturn()이런 식으로 메소드 호출을 연결할 수도 있습니다.

doReturn(null).doReturn(anotherInstance).when(mock).method();

귀엽지 않니 :)


4

MultipleAnswer모든 통화에서 다른 답변을 스텁하는 데 도움이 되는 클래스를 구현했습니다 . 다음은 코드 조각입니다.

private final class MultipleAnswer<T> implements Answer<T> {

    private final ArrayList<Answer<T>> mAnswers;

    MultipleAnswer(Answer<T>... answer) {
        mAnswers = new ArrayList<>();
        mAnswers.addAll(Arrays.asList(answer));
    }

    @Override
    public T answer(InvocationOnMock invocation) throws Throwable {
        return mAnswers.remove(0).answer(invocation);
    }
}

1
짧고 간단하며 읽기 쉬운 방식으로 해당 객체를 초기화 할 수 있습니까?
usr-local-ΕΨΗΕΛΩΝ

1

다음은 다른 메소드 호출에서 다른 인수를 리턴하는 공통 메소드로 사용될 수 있습니다. 우리가해야 할 일은 각 호출에서 객체를 검색 해야하는 순서로 배열을 전달해야한다는 것입니다.

@SafeVarargs
public static <Mock> Answer<Mock> getAnswerForSubsequentCalls(final Mock... mockArr) {
    return new Answer<Mock>() {
       private int count=0, size=mockArr.length;
       public Mock answer(InvocationOnMock invocation) throws throwable {
           Mock mock = null;
           for(; count<size && mock==null; count++){
                mock = mockArr[count];
           }

           return mock;    
       } 
    }
}

전의. getAnswerForSubsequentCalls(mock1, mock3, mock2);첫 번째 호출에서 mock1 개체, 두 번째 호출에서 mock3 개체 및 세 번째 호출에서 mock2 개체를 반환합니다. 처럼 사용할 수 있어야 when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2)); 이 것은 거의 비슷합니다when(something()).thenReturn(mock1, mock3, mock2);


1

8 년 전 @ @ Igor Nikolaev의 답변과 관련하여 Java 8에서 사용할 수 Answer있는 람다 식을 사용하면 다소 단순화 할 수 있습니다 .

when(someMock.someMethod()).thenAnswer(invocation -> {
    doStuff();
    return;
});

또는 더 간단하게 :

when(someMock.someMethod()).thenAnswer(invocation -> doStuff());

1

BDD 스타일 :

import static org.mockito.BDDMockito.*;
...
    @Test
    void submit() {
        given(yourMock.yourMethod()).willReturn(1, 2, 3);

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.