Mockito Matchers isA、any、eq 和 same 之间有什么区别?
What's the difference between Mockito Matchers isA, any, eq, and same?
我对它们之间的区别以及在哪种情况下选择哪个感到困惑。有些差异可能很明显,例如 any
和 eq
,但我将它们全部包括在内只是为了确定。
我想知道它们的区别,因为我遇到了这个问题:
我在控制器 class
中有这个 POST 方法
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
class), 和 return res
, 就像第一个一样。我知道使用 MockMvc 方法是不可能的(或者是吗?),因为在实际调用中传递的对象总是与在模拟中传递的对象不同。无论如何我能做到吗?或者这样做是否有意义?或者我应该满足于使用 any(Request.class)
?我试过 eq
、same
,但都失败了。
如果您的 Request.class 实现了 equals,那么您可以使用 eq():
Bar bar = getBar();
when(fooService.fooFxn(eq(bar)).then...
以上当会在
激活
fooService.fooFxn(otherBar);
如果
otherBar.equals(bar);
或者,如果您希望模拟适用于其他输入子集(例如,所有 Bar.getBarLength()>10 的条形图),您可以创建一个匹配器。我不经常看到这种模式,所以通常我将 Matcher 创建为私有 class:
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...
希望对您有所帮助!
any()
checks absolutely nothing. Since Mockito 2.0, any(T.class)
共享 isA
语义,表示“任何 T
”或正确的“任何 T
类型的实例”。
This is a change compared to Mockito 1.x, where any(T.class)
除了在 Java 8 之前保存了一个转换之外,什么也没检查:“任何类型的对象,给定的 class 不是必需的。class 参数是提供只是为了避免投射。"
isA(T.class)
检查参数 instanceof T
,暗示它是非空的。
same(obj)
检查参数是否引用与 obj
相同的实例,因此 arg == obj
为真。
eq(obj)
根据其 equals
方法检查参数是否等于 obj
。如果您在不使用匹配器的情况下传递真实值,这也是行为。
请注意,除非覆盖 equals
,否则您将看到默认的 Object.equals 实现,其行为与 same(obj)
.
相同
如果您需要更精确的定制,您可以为自己的谓词使用适配器:
- 对于 Mockito 1.x,将
argThat
与自定义 Hamcrest Matcher<T>
一起使用,它可以准确选择您需要的对象。
- 对于 Mockito 2.0 及更高版本,使用
Matchers.argThat
with a custom org.mockito.ArgumentMatcher<T>
, or MockitoHamcrest.argThat
和自定义 Hamcrest Matcher<T>
。
您也可以使用 refEq
, which uses reflection to confirm object equality; Hamcrest has a similar implementation with SamePropertyValuesAs for public bean-style properties. Note that on GitHub issue #1800 proposes deprecating and removing refEq
,在那个问题中,您可能更喜欢 eq
来更好地让您的 class 更好地封装他们的平等感。
我对它们之间的区别以及在哪种情况下选择哪个感到困惑。有些差异可能很明显,例如 any
和 eq
,但我将它们全部包括在内只是为了确定。
我想知道它们的区别,因为我遇到了这个问题: 我在控制器 class
中有这个 POST 方法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
class), 和 return res
, 就像第一个一样。我知道使用 MockMvc 方法是不可能的(或者是吗?),因为在实际调用中传递的对象总是与在模拟中传递的对象不同。无论如何我能做到吗?或者这样做是否有意义?或者我应该满足于使用 any(Request.class)
?我试过 eq
、same
,但都失败了。
如果您的 Request.class 实现了 equals,那么您可以使用 eq():
Bar bar = getBar();
when(fooService.fooFxn(eq(bar)).then...
以上当会在
激活fooService.fooFxn(otherBar);
如果
otherBar.equals(bar);
或者,如果您希望模拟适用于其他输入子集(例如,所有 Bar.getBarLength()>10 的条形图),您可以创建一个匹配器。我不经常看到这种模式,所以通常我将 Matcher 创建为私有 class:
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...
希望对您有所帮助!
any()
checks absolutely nothing. Since Mockito 2.0,any(T.class)
共享isA
语义,表示“任何T
”或正确的“任何T
类型的实例”。This is a change compared to Mockito 1.x, where
any(T.class)
除了在 Java 8 之前保存了一个转换之外,什么也没检查:“任何类型的对象,给定的 class 不是必需的。class 参数是提供只是为了避免投射。"isA(T.class)
检查参数instanceof T
,暗示它是非空的。same(obj)
检查参数是否引用与obj
相同的实例,因此arg == obj
为真。eq(obj)
根据其equals
方法检查参数是否等于obj
。如果您在不使用匹配器的情况下传递真实值,这也是行为。请注意,除非覆盖
相同equals
,否则您将看到默认的 Object.equals 实现,其行为与same(obj)
.
如果您需要更精确的定制,您可以为自己的谓词使用适配器:
- 对于 Mockito 1.x,将
argThat
与自定义 HamcrestMatcher<T>
一起使用,它可以准确选择您需要的对象。 - 对于 Mockito 2.0 及更高版本,使用
Matchers.argThat
with a customorg.mockito.ArgumentMatcher<T>
, orMockitoHamcrest.argThat
和自定义 HamcrestMatcher<T>
。
您也可以使用 refEq
, which uses reflection to confirm object equality; Hamcrest has a similar implementation with SamePropertyValuesAs for public bean-style properties. Note that on GitHub issue #1800 proposes deprecating and removing refEq
,在那个问题中,您可能更喜欢 eq
来更好地让您的 class 更好地封装他们的平等感。