看这个例子:
class Foo { }
class Bar {
void takeIt(int i, String arg) { System.out.println(arg + i); }
}
public class Mcve {
@Test
public void passes() {
Foo foo = Mockito.mock(Foo.class);
Bar bar = Mockito.mock(Bar.class);
bar.takeIt(42, "surprise: " + foo);
String substring = "surprise: " + foo;
Mockito.verify(bar).takeIt(ArgumentMatchers.eq(42),
ArgumentMatchers.contains(substring));
}
@Test
public void fails() {
Foo foo = Mockito.mock(Foo.class);
Bar bar = Mockito.mock(Bar.class);
bar.takeIt(42, "surprise: " + foo);
Mockito.verify(bar).takeIt(ArgumentMatchers.eq(42),
ArgumentMatchers.contains("surprise: " + foo));
}
}
这两个测试几乎相同,唯一的区别是:用于contains()
匹配器的字符串在 中预先计算passes()
,但在 中内联fails()
。
fails()
呕吐:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
-> at com.ibm.hwmca.z.svm.zhyp.managed.Mcve.fails(Mcve.java:43)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
For more info see javadoc for Matchers class.
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at Mcve.fails(Mcve.java:43)
...
(显然:错误消息是完全错误的,因为上面的代码对所有参数都使用了匹配器)
更有趣的是:它只会在超过 1 个要匹配的参数时失败(如果一个从 中删除int
参数gimme()
,并且只是传递/匹配该字符串参数:传递)。
谁能准确解释这里发生了什么,有没有办法做这样的匹配contains("surprise: " + foo)
,比如foo
被 Mockito 嘲笑?
当然,这实际上是指 MCVE。从我们环境中失败的单元测试到这里的这个例子,我花了 3 个小时。
在真实环境中,Bar 类是一个模拟的日志工具。Foo 对象代表一些由一些假持久层创建的“数据实体”。我必须验证生产代码确实记录了特定信息,并且其中一些信息来自伪造的数据对象。