作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
Mockito 参数匹配器(例如 any
、 argThat
、 eq
、 same
和 ArgumentCaptor.capture()
)的行为与 Hamcrest 匹配器非常不同。
Answer
时可能导致 NullPointerException s 或使用时 (Integer) any()
等最佳答案
Mockito matchers是静态方法和对这些方法的调用,它们在调用 when
期间代表参数。和 verify
.
Hamcrest matchers (存档版本)(或 Hamcrest 风格的匹配器)是实现 Matcher<T>
的无状态、通用对象实例。并公开一个方法 matches(T)
如果对象匹配匹配器的条件,则返回 true。它们旨在没有副作用,并且通常用于断言,例如下面的断言。
/* Mockito */ verify(foo).setPowerLevel(gt(9000));
/* Hamcrest */ assertThat(foo.getPowerLevel(), is(greaterThan(9000)));
Mockito 匹配器存在,与 Hamcrest 风格的匹配器分开,因此匹配表达式的描述直接适合方法调用:
Mockito matchers return T
where Hamcrest matcher methods return Matcher objects (of type Matcher<T>
).
eq
,
any
,
gt
, 和
startsWith
在
org.mockito.Matchers
和
org.mockito.AdditionalMatchers
.还有适配器,它们在 Mockito 版本之间发生了变化:
Matchers
精选一些调用(例如 intThat
或 argThat
)是直接接受 Hamcrest 匹配器作为参数的 Mockito 匹配器。 ArgumentMatcher<T>
扩展 org.hamcrest.Matcher<T>
,它用于内部 Hamcrest 表示,是一个 Hamcrest 匹配器基类,而不是任何类型的 Mockito 匹配器。 Matchers
调用短语为 intThat
或 argThat
包装 ArgumentMatcher<T>
不再实现的对象 org.hamcrest.Matcher<T>
但以类似的方式使用。 Hamcrest 适配器,例如 argThat
和 intThat
仍然可用,但已移至 MockitoHamcrest
反而。 /* Mockito matcher intThat adapting Hamcrest-style matcher is(greaterThan(...)) */
verify(foo).setPowerLevel(intThat(is(greaterThan(9000))));
在上述声明中:
foo.setPowerLevel
是一种接受
int
的方法.
is(greaterThan(9000))
返回
Matcher<Integer>
,这不能用作
setPowerLevel
论据。 Mockito 匹配器
intThat
包装那个 Hamcrest-style Matcher 并返回一个
int
所以它可以作为一个论点出现; Mockito 匹配器喜欢
gt(9000)
会将整个表达式包装到单个调用中,如示例代码的第一行。
when(foo.quux(3, 5)).thenReturn(true);
当不使用参数匹配器时,Mockito 会记录你的参数值并将它们与它们的
equals
进行比较。方法。
when(foo.quux(eq(3), eq(5))).thenReturn(true); // same as above
when(foo.quux(anyInt(), gt(5))).thenReturn(true); // this one's different
当你调用像
any
这样的匹配器时或
gt
(大于),Mockito 存储一个匹配器对象,该对象使 Mockito 跳过该相等性检查并应用您选择的匹配。在
argumentCaptor.capture()
的情况下它存储一个匹配器,用于保存其参数以供以后检查。
null
. Mockito 尝试返回一个安全、适当的虚拟值,例如
anyInt()
的值为 0。或
any(Integer.class)
或空的
List<String>
为
anyListOf(String.class)
.然而,由于类型删除,Mockito 缺乏类型信息来返回任何值,但
null
为
any()
或
argThat(...)
, 如果尝试“自动拆箱”
null
可能会导致 NullPointerException原始值(value)。
eq
和
gt
取参数值;理想情况下,应在 stub /验证开始之前计算这些值。在模拟另一个调用的过程中调用模拟会干扰 stub 。
thenReturn(anyInt())
或
thenReturn(any(Foo.class))
例如,在 Mockito。 Mockito 需要确切地知道在 stub 调用中返回哪个实例,并且不会为您选择任意的返回值。
and
, or
, and not
这样的匹配器除外。 .这完全对应(并依赖于)
evaluation order of Java ,它在调用方法之前从左到右计算参数:
when(foo.quux(anyInt(), and(gt(10), lt(20)))).thenReturn(true);
[6] [5] [1] [4] [2] [3]
这将:
anyInt()
到堆栈。 gt(10)
到堆栈。 lt(20)
到堆栈。 gt(10)
和 lt(20)
并添加 and(gt(10), lt(20))
. foo.quux(0, 0)
,它(除非另外 stub )返回默认值 false
.内部 Mockito 标记 quux(int, int)
作为最近的电话。 when(false)
,丢弃其参数并准备 stub 方法 quux(int, int)
在 5 中确定。仅有的两个有效状态是堆栈长度为 0(相等)或 2(匹配器),并且堆栈上有两个匹配器(步骤 1 和 4),因此 Mockito 使用 any()
stub 该方法。匹配器的第一个参数和 and(gt(10), lt(20))
为它的第二个参数并清除堆栈。 quux(anyInt(), 0)
和 quux(0, anyInt())
.它们看起来都像是给 quux(0, 0)
的电话堆栈上有一个 int 匹配器。因此,如果您使用一个匹配器,则必须匹配所有参数。int between10And20 = and(gt(10), lt(20));
/* BAD */ when(foo.quux(anyInt(), between10And20)).thenReturn(true);
// Mockito sees the stack as the opposite: and(gt(10), lt(20)), anyInt().
public static int anyIntBetween10And20() { return and(gt(10), lt(20)); }
/* OK */ when(foo.quux(anyInt(), anyIntBetween10And20())).thenReturn(true);
// The helper method calls the matcher methods in the right order.
when
之外,堆栈应该始终为空。或 verify
,但 Mockito 无法自动检查。Mockito.validateMockitoUsage()
手动检查.when
, Mockito 实际上调用了有问题的方法,如果您已 stub 该方法抛出异常(或需要非零或非空值),则该方法将抛出异常。doReturn
和 doAnswer
(etc) 不调用实际方法,通常是一个有用的替代方法。eq
匹配器的答案),Mockito 将根据该调用检查堆栈长度,并且可能会失败。final
方法调用可能不会抛出异常,但你可能会得到一个 InvalidUseOfMatchersException当您下次与模拟交互时,从流浪匹配器中获取。when
之外使用匹配器或 verify
称呼。匹配器永远不应该用作 stub 返回值或字段/变量。(Integer) any()
any(Integer.class)
时返回 null返回 0;这可能会导致 NullPointerException
如果您期待 int
而不是整数。无论如何,首选 anyInt()
,这将返回零并跳过自动装箱步骤。when(foo.bar(any())).thenReturn(baz)
实际上会拨打 foo.bar(null)
,您可能已经在接收空参数时 stub 以抛出异常。切换到 doReturn(baz).when(foo).bar(any())
skips the stubbed behavior .validateMockitoUsage
在您的 tearDown
或 @After
方法(运行者会自动为你做)。这将有助于确定您是否滥用了匹配器。validateMockitoUsage
的调用直接在您的代码中。如果你有任何东西在堆栈上,这将抛出,这是一个不好的症状的好警告。关于java - Mockito 匹配器如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22822512/
我是一名优秀的程序员,十分优秀!