Какая разница между Mockito Matchers isA, any, eq и тому же?
Я смущен тем, какая разница между ними, и какой из них выбрать в этом случае. Некоторая разница может быть очевидна, например, any
и eq
, но я включаю их все, чтобы быть уверенными.
Мне интересно об их различиях, потому что я столкнулся с этой проблемой:
У меня есть этот метод POST в классе Controller
public Response doSomething(@ResponseBody Request request) {
return someService.doSomething(request);
}
И хотел бы выполнить unit test на этом контроллере.
У меня две версии. Первый из них простой, как этот
@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));
}
Но я хотел использовать подход MockMvc, как этот
@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")));
}
Оба работают хорошо. Но я хотел, чтобы мой someServiceMock.doSomething()
в подходе MockMvc получил req
, или, по крайней мере, объект, который имеет те же переменные, что и req
(а не только любой класс Request
), и возвращает res
, как и первый. Я знаю, что невозможно использовать подход MockMvc (или это?), Потому что объект, переданный в реальном вызове, всегда отличается от объекта, переданного в макете. В любом случае, я могу это достичь? Или это даже имеет смысл сделать это? Или я должен быть удовлетворен с помощью any(Request.class)
? Я пробовал eq
, same
, но все они терпят неудачу.
Спасибо заранее.
Надеюсь, я хорошо себя объяснил.
Ответы
Ответ 1
-
any()
абсолютно ничего не проверяет. В Mockito 1.x, any(T.class)
также абсолютно ничего не проверяет, а также сохраняет вас приложением (до Java 8).
Это связано с изменениями в Mockito 2.0 и более поздних версиях, когда any(T.class)
будет делиться семантикой isA
, означающей "any T
" или "правильно" экземпляр типа T
". any()
все равно ничего не проверит.
-
isA(T.class)
проверяет, что аргумент instanceof T
, подразумевая, что он не равен нулю.
-
same(obj)
проверяет, что аргумент является тем же самым экземпляром, что и obj
, так что arg == obj
является истинным.
-
eq(obj)
проверяет, что аргумент равен obj
в соответствии с его методом equals
. Это также поведение, если вы передаете реальные значения без использования сокетов.
Обратите внимание, что если переопределить equals
, вы увидите стандартную реализацию Object.equals по умолчанию, которая будет иметь такое же поведение, как same(obj)
.
Если вам нужна более точная настройка, вы можете использовать адаптер для своего собственного предиката:
- Для Mockito 1.x используйте
argThat
с пользовательским Hamcrest Matcher<T>
, который выбирает именно те объекты, которые вам нужны.
- Для Mockito 2.0 и выше используйте
Matchers.argThat
с пользовательским org.mockito.ArgumentMatcher<T>
или MockitoHamcrest.argThat
с пользовательским Hamcrest Matcher<T>
.
Ответ 2
Если ваш Request.class реализует equals, вы можете использовать eq():
Bar bar = getBar();
when(fooService.fooFxn(eq(bar)).then...
Вышеуказанное, если активировать на
fooService.fooFxn(otherBar);
если
otherBar.equals(bar);
В качестве альтернативы, если вы хотите, чтобы макет работал для некоторого другого подмножества ввода (например, все бары с Bar.getBarLength() > 10), вы могли бы создать Matcher. Я не вижу этот шаблон слишком часто, поэтому обычно я создаю Matcher как частный класс:
private static class BarMatcher extends BaseMatcher<Bar>{
...//constructors, descriptions, etc.
public boolean matches(Object otherBar){
//Checks, casts, etc.
return otherBar.getBarLength()>10;
}
}
Затем вы должны использовать этот матчи следующим образом:
when(fooService.fooFxn(argThat(new BarMatcher())).then...
Надеюсь, что это поможет!