IT story

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

hot-time 2020. 4. 5. 20:36
반응형

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


스텁 된 메소드가 후속 호출에서 다른 오브젝트를 리턴하도록하는 방법이 있습니까? 의 결정되지 않은 응답을 테스트하기 위해이 작업을 수행하고 싶습니다 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 (...) { }        
}

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();

어때요?

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

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


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

그래서 당신은 전화 할 수

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에 대한 자세한 정보 .


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

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

귀엽지 않니 :)


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);
    }
}

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

@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);


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

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

또는 더 간단하게 :

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

BDD 스타일 :

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

참고 URL : https://stackoverflow.com/questions/8088179/using-mockito-with-multiple-calls-to-the-same-method-with-the-same-arguments

반응형