Je veux stub une classe de référentiel pour tester une autre classe (classe Holder) qui a un référentiel. L'interface du référentiel prend en charge les opérations CRUD et dispose de nombreuses méthodes, mais mon test unitaire sur la classe Holder n'a besoin que d'en appeler deux. L'interface du référentiel:
public interface IRepo {
public void remove(String... sarr);
public void add(String... sarr);
//Lots of other methods I don't need now
}
Je veux créer une maquette de référentiel qui peut stocker des instances, définir la logique pour add
et remove
uniquement, et fournir également un moyen de vérifier ce qui est stocké après avoir appelé add et supprimer.
Si je fais:
IRepo repoMock = mock(IRepo.class);
Ensuite, j'ai un objet stupide qui ne fait rien sur chaque méthode. C'est OK, maintenant je dois juste définir le comportement pour ajouter et supprimer.
Je pourrais créer un Set<String>
et stub uniquement ces deux méthodes pour travailler sur l'ensemble. Ensuite, j'instancierais un support qui a un IRepo, injecter la maquette partiellement tronquée, et après avoir exercé le support, vérifier l'ensemble pour vérifier qu'il contient ce qu'il devrait.
J'ai réussi à bloquer partiellement une méthode void comme remove
en utilisant la méthode obsolète stubVoid
:
Set<String> mySet = new HashSet<>();
stubVoid(repoMock).toAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
String[] stringsToDelete = (String[]) args[0];
mySet.removeAll(Arrays.asList(stringsToDelete));
return null;
}
}).on().remove(Matchers.<String>anyVararg());
Mais est obsolète, et ce n'est pas beaucoup mieux que de créer une implémentation partielle pour IRepo. Y a-t-il une meilleure façon?
REMARQUE: Java 7 réponses uniquement s'il vous plaît, cela devrait fonctionner dans Android.
Vous pouvez utiliser
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
//DO SOMETHING
return null;
}
}).when(...).remove(Matchers.<String>anyVararg());
Du Javadoc:
Utilisez doAnswer () lorsque vous souhaitez bloquer une méthode void avec Answer générique.
Le stubbing voids nécessite une approche différente de Mockito.when (Object) car le compilateur n'aime pas les méthodes void entre crochets ...
Exemple:
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Mock mock = invocation.getMock();
return null;
}}).when(mock).someMethod();
Voir des exemples en javadoc pour Mockito
Supposons que vous ayez
public class IFace {
public void yourMethod() {
}
}
Ensuite, pour vous moquer, vous avez besoin
IFace mock = Mockito.mock(IFace.class);
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
//PUT YOUR CODE HERE
return null;
}
}).when(mock).yourMethod();
Si vous n'aimez vraiment pas return null
dans votre implémentation de Answer
, vous pouvez créer votre propre implémentation Answer qui délègue à une méthode void:
public abstract class DoesSomethingAnswer implements Answer<Void> {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
doSomething(invocation);
return null;
}
protected abstract void doSomething(InvocationOnMock invocation);
}
Ensuite, votre test a une ligne de moins:
Set<String> mySet = new HashSet<>();
Mockito.doAnswer(new DoesSomethingAnswer() {
@Override
protected void doSomething(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
String[] stringsToDelete = (String[]) args[0];
mySet.removeAll(Arrays.asList(stringsToDelete));
}
}).when(repoMock).remove(Matchers.<String> anyVararg());
Ou, si vous avez juste besoin des arguments de l'invocation:
public abstract class DoesSomethingAnswer implements Answer<Void> {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
doSomething(invocation.getArguments());
return null;
}
protected abstract void doSomething(Object[] args);
}