Какая разница между Mockito Matchers - это A, any, eq, и то же самое?
Меня смущает, в чем разница между ними, и какой выбрать в каком случае. Некоторая разница может быть очевидной, как any
а также eq
Но я включаю их всех просто чтобы быть уверенным.
Я удивляюсь их различиям, потому что я столкнулся с этой проблемой: у меня есть этот метод POST в классе Controller
public Response doSomething(@ResponseBody Request request) {
return someService.doSomething(request);
}
И хотел бы выполнить модульное тестирование на этом контроллере. У меня есть две версии. Первый простой, как этот
@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
, но все они терпят неудачу.
Заранее спасибо. Надеюсь, я все хорошо объяснил.
2 ответа
any()
абсолютно ничего не проверяет. В Mockito 1.x,any(T.class)
также абсолютно ничего не проверяет, но также сохраняет вас приведения (до Java 8).Это связано с изменениями в Mockito 2.0 и выше, когда
any(T.class)
будет делитьсяisA
семантика означает "любой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
с кастомным HamcrestMatcher<T>
который выбирает именно те объекты, которые вам нужны. - Для Mockito 2.0 и выше используйте
Matchers.argThat
с обычаемorg.mockito.ArgumentMatcher<T>
, или жеMockitoHamcrest.argThat
с кастомным HamcrestMatcher<T>
,
Если ваш 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...
Надеюсь, это поможет!