web-dev-qa-db-fra.com

Quelle est la différence entre Mockito Matchers isA, any, eq et same?

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é.

33
Silly Sally
  • 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:

  • Pour Mockito 1.x, utilisez argThat avec un Hamcrest Matcher<T> Personnalisé qui sélectionne exactement les objets dont vous avez besoin.
  • Pour Mockito 2.0 et les versions ultérieures, utilisez Matchers.argThat Avec un org.mockito.ArgumentMatcher<T> Personnalisé, ou MockitoHamcrest.argThat Avec un Hamcrest Matcher<T> Personnalisé.
64
Jeff Bowman

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é!

3
Alex Pruss