Je suis confus sur quelle est la différence entre eux, et lequel choisir dans quel cas. Certaines différences pourraient être évidentes, comme any
et eq
, mais je les inclue toutes pour être sûr.
Je me demande quelles sont leurs différences parce que j’ai rencontré ce problème: j’ai cette méthode POST dans une classe de contrôleur
public Response doSomething(@ResponseBody Request request) {
return someService.doSomething(request);
}
Et voudrait effectuer un test unitaire sur ce contrôleur. J'ai deux versions. Le premier est le simple, comme celui-ci
@Test
public void testDoSomething() {
//initialize ObjectMapper mapper
//initialize Request req and Response res
when(someServiceMock.doSomething(req)).thenReturn(res);
Response actualRes = someController.doSomething(req);
assertThat(actualRes, is(res));
}
Mais je voulais utiliser une approche MockMvc, comme celle-ci
@Test
public void testDoSomething() {
//initialize ObjectMapper mapper
//initialize Request req and Response res
when(someServiceMock.doSomething(any(Request.class))).thenReturn(res);
mockMvc.perform(post("/do/something")
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(req))
)
.andExpect(status().isOk())
.andExpect(jsonPath("$message", is("done")));
}
Les deux fonctionnent bien. Mais je voulais que ma someServiceMock.doSomething()
dans l’approche MockMvc reçoive req
, ou au moins un objet ayant les mêmes valeurs de variable que req
(et pas n'importe lequel Request
class), et retourne res
, exactement comme le premier. Je sais qu'il est impossible d'utiliser l'approche MockMvc (ou l'est-il?), Car l'objet transmis dans l'appel lui-même est toujours différent de l'objet transmis dans la maquette. Est-ce que je peux y arriver? Ou est-ce même logique de faire cela? Ou devrais-je être satisfait en utilisant any(Request.class)
? J'ai essayé eq
, same
, mais tous échouent.
Merci d'avance. J'espère que je me suis bien expliqué.
any()
ne vérifie absolument rien. Dans Mockito 1.x, any(T.class)
ne vérifie également absolument rien, mais vous enregistre également un casting (avant Java 8).
Ceci est dû à un changement dans Mockito 2.0 et au-delà , lorsque any(T.class)
partagera isA
la sémantique signifie "tout T
" ou correctement "tout instance de type T
". any()
ne vérifiera toujours absolument rien.
isA(T.class)
vérifie que l'argument instanceof T
, ce qui implique qu'il est non nul.
same(obj)
vérifie que l'argument est la même instance que obj
, de sorte que arg == obj
est vrai.
eq(obj)
vérifie que l'argument est égal à obj
selon sa méthode equals
. C'est également le comportement si vous transmettez des valeurs réelles sans utiliser d'appariement.
Notez qu'à moins que equals
ne soit remplacé, vous verrez l'implémentation par défaut d'Object.equals, qui aurait le même comportement que same(obj)
.
Si vous avez besoin d'une personnalisation plus précise, vous pouvez utiliser un adaptateur pour votre propre prédicat:
argThat
avec un Hamcrest Matcher<T>
Personnalisé qui sélectionne exactement les objets dont vous avez besoin.Matchers.argThat
Avec un org.mockito.ArgumentMatcher<T>
Personnalisé, ou MockitoHamcrest.argThat
Avec un Hamcrest Matcher<T>
Personnalisé.Si votre Request.class implémente des équivalents, vous pouvez utiliser eq ():
Bar bar = getBar();
when(fooService.fooFxn(eq(bar)).then...
Ce qui précède lorsque serait activé le
fooService.fooFxn(otherBar);
si
otherBar.equals(bar);
Sinon, si vous voulez que la maquette fonctionne pour un autre sous-ensemble d'entrées (par exemple, toutes les mesures avec Bar.getBarLength ()> 10), vous pouvez créer un Matcher. Je ne vois pas ce modèle trop souvent, donc je crée généralement Matcher en tant que classe privée:
private static class BarMatcher extends BaseMatcher<Bar>{
...//constructors, descriptions, etc.
public boolean matches(Object otherBar){
//Checks, casts, etc.
return otherBar.getBarLength()>10;
}
}
Vous utiliseriez alors ce matcher comme suit:
when(fooService.fooFxn(argThat(new BarMatcher())).then...
J'espère que ça t'as aidé!