Jaka jest różnica między Mockito Matchers isA, any, eq i same?

Jestem zdezorientowany, jaka jest różnica między nimi, i który z nich wybrać w jakim przypadku. Niektóre różnice mogą być oczywiste, jak any i eq, ale włączam je wszystkie dla pewności.

Zastanawiam się nad ich różnicami, ponieważ natknąłem się na ten problem: Mam tę metodę POST w klasie kontrolera

public Response doSomething(@ResponseBody Request request) {
    return someService.doSomething(request);
}

I chciałby przeprowadzić test jednostkowy na tym kontrolerze. Mam dwie wersje. Pierwszy jest prosty, jak to

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

Ale chciałem użyć metody MockMvc, takiej jak ta

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

Oba działają dobrze. Ale chciałem, aby moja someServiceMock.doSomething() w podejściu MockMvc otrzymała req, lub przynajmniej obiekt, który ma takie same wartości zmiennych jak req (nie byle jaką Request klasę), i zwróciła res, tak jak pierwsza. Wiem, że to niemożliwe przy użyciu podejścia MockMvc (a może jest?), ponieważ obiekt przekazany w rzeczywistym wywołaniu zawsze różni się od obiektu przekazanego w makiecie. Czy w ogóle mogę osiągnąć? Czy to ma sens? Czy powinienem być usatysfakcjonowany używając any(Request.class)? Próbowałem eq, same, ale wszystkie zawodzą.

Author: Willi Mentzel, 2015-06-17

2 answers

  • any() nic nie sprawdza. W Mockito 1.x, any(T.class) również nic nie sprawdza, ale również zapisuje Ci obsadę (przed Javą 8).

    Jest to spowodowane zmianą w Mockito 2.0 i później, kiedy any(T.class) będzie dzielić semantykę isA na "any T" lub właściwie "any instance of type T". any() nadal niczego nie sprawdzi.

  • isA(T.class) sprawdza, czy argument instanceof T, sugerując, że jest inny niż null.

  • same(obj) kontrole że argument jest tą samą instancją co obj, tak że arg == obj jest prawdą.

  • eq(obj) sprawdza, czy argument jest równy obj zgodnie z jego metodą equals. Jest to również zachowanie, jeśli przekazujesz prawdziwe wartości bez użycia matcherów.

    Zauważ, że jeśli equals nie zostanie nadpisana, zobaczysz obiekt domyślny.równa się implementacja, która miałaby takie samo zachowanie jak same(obj).

Jeśli potrzebujesz dokładniejszego dostosowania, możesz użyć adaptera do Twoje własne orzeczenie:

  • Dla Mockito 1.x, Użyj {[17] } z niestandardowym Hamcrest Matcher<T>, który wybiera dokładnie obiekty, których potrzebujesz.
  • W przypadku Mockito 2.0 i nowszych, użyj Matchers.argThat z niestandardowym org.mockito.ArgumentMatcher<T> lub MockitoHamcrest.argThat z niestandardowym Hamcrest Matcher<T>.
 88
Author: Jeff Bowman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:42

Jeśli Twoja prośba.klasa implementuje równe, wtedy możesz użyć eq ():

Bar bar = getBar();
when(fooService.fooFxn(eq(bar)).then...

Powyższe Kiedy uaktywni się na

fooService.fooFxn(otherBar);

If

otherBar.equals(bar);

Alternatywnie, jeśli chcesz, aby makieta działała dla jakiegoś innego podzbioru danych wejściowych (na przykład, wszystkie paski z paskiem.getBarLength ()>10), można utworzyć Matcher. Nie widzę tego wzoru zbyt często, więc zazwyczaj tworzę Matcher jako klasę prywatną: {]}

private static class BarMatcher extends BaseMatcher<Bar>{
...//constructors, descriptions, etc.
  public boolean matches(Object otherBar){
     //Checks, casts, etc.
     return otherBar.getBarLength()>10;
  }
}

Wtedy użyłbyś tego matchera jako "follows": {]}

when(fooService.fooFxn(argThat(new BarMatcher())).then...
Mam nadzieję, że to pomoże!
 3
Author: Alex Pruss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-17 11:55:33