【发布时间】:2013-06-10 15:24:12
【问题描述】:
我们在 Mockito 上遇到了非常糟糕的问题。
代码:
public class Baz{
private Foo foo;
private List list;
public Baz(Foo foo){
this.foo = foo;
}
public void invokeBar(){
list = Arrays.asList(1,2,3);
foo.bar(list);
list.clear();
}
}
public class BazTest{
@Test
void testBarIsInvoked(){
Foo mockFoo = mock(Foo.class);
Baz baz = new Baz(mockFoo);
baz.invokeBar();
verify(mockFoo).bar(Arrays.asList(1,2,3));
}
}
这会导致如下错误消息:
Arguments are different! Wanted:
foo.bar([1,2,3]);
Actual invocation has different arguments:
foo.bar([]);
刚刚发生的事情:
Mockito 记录 reference 到 list 而不是 list 的副本,因此在上面的代码中,Mockito 验证 修改版本(空列表,[])而不是调用期间实际传递的那个 ([1,2,3])!
问题:
除了像下面那样做一个防御性副本(这实际上有帮助,但我们不喜欢这个解决方案)之外,还有什么优雅而干净的解决方案吗?
public void fun(){
list = Arrays.asList(1,2,3);
foo.bar(new ArrayList(list));
list.clear();
}
我们不想修改正确生产代码并降低其性能只是为了解决测试的技术问题。
我在这里问这个问题是因为这似乎是 Mockito 的常见问题。还是我们做错了什么?
附言。这不是一个真实的代码,所以请不要问我们为什么要创建一个列表然后清除它等等。在真实的代码中,我们确实需要做类似的事情:-)。
【问题讨论】:
-
您是否真的在同一参数类的不同实例上进行验证?
-
@fge 是的,我无法访问测试代码中的原始实例,因此我需要在测试中创建一个具有预期内容的新参数实例。
标签: java unit-testing pass-by-reference mockito