web-dev-qa-db-fra.com

Utiliser Mockito avec plusieurs appels de la même méthode avec les mêmes arguments

Existe-t-il un moyen de faire en sorte qu'une méthode stubbed retourne différents objets lors d'appels ultérieurs? J'aimerais faire cela pour tester les réponses non déterminées d'un ExecutorCompletionService. c’est-à-dire pour vérifier que, quel que soit l’ordre de retour des méthodes, le résultat reste constant.

Le code que je cherche à tester ressemble à ceci.

// 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 (...) { }        
}
241
Emma

Vous pouvez le faire en utilisant la méthode thenAnswer (lors du chaînage avec when ):

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

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

        return 2;
    }
});

Ou en utilisant la méthode équivalente doAnswer :

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

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

        return 2;
    }
}).when(someMock).someMethod();
211
Igor Nikolaev

Que diriez-vous

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

Vous pouvez mettre autant d'arguments que vous le souhaitez dans les crochets de thenReturn, à condition qu'ils soient tous du type correct. La première valeur sera renvoyée la première fois que la méthode est appelée, puis la deuxième réponse, etc. La dernière valeur sera renvoyée à plusieurs reprises une fois que toutes les autres valeurs auront été utilisées.

550
Dawood ibn Kareem

Comme précédemment indiqué , presque tous les appels sont chaînables.

Pour que tu puisses appeler

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

Plus d'infos dans Documentation de Mockito .

115
Raystorm

Vous pouvez même chaîner doReturn() invocations de méthode comme ceci

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

mignon n'est-ce pas :)

63

J'ai mis en place une classe MultipleAnswer qui m'aide à noter différentes réponses à chaque appel. Voici le morceau de code:

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

La méthode suivante peut être utilisée comme méthode commune pour renvoyer différents arguments sur différents appels de méthode. La seule chose à faire est de passer un tableau avec l'ordre dans lequel les objets doivent être récupérés à chaque appel.

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

Ex. getAnswerForSubsequentCalls(mock1, mock3, mock2); retournera l'objet mock1 lors du premier appel, l'objet mock3 lors du deuxième appel et l'objet mock2 lors du troisième appel. Devrait être utilisé comme when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2)); Ceci est presque similaire à when(something()).thenReturn(mock1, mock3, mock2);

1
yuva 443

En rapport avec la réponse de @ [Igor Nikolaev] d'il y a 8 ans, l'utilisation d'un Answer peut être quelque peu simplifiée à l'aide d'un expression lambda disponible dans Java 8.

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

ou plus simplement:

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

Style BDD:

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