Mockito可以在方法调用时根据它们的值验证参数吗?
我有一个Foo
类是SUT和Bar
类,这是它的合作者。 Foo
在Bar
上调用run(List<Object> values)
,将“expectedList
”作为参数。然后,Foo
将为此List
添加几个元素,以使其状态与调用run()
时的状态不同。这是我的测试案例。Mockito可以在方法调用时根据它们的值验证参数吗?
@Test
public void testFoo() {
Bar collaborator = spy(new Bar());
Foo sut = new Foo(collaborator);
verify(collaborator).run(expectedList);
}
注意,合作者实际上是一个间谍对象,而不是模仿。此测试用例将失败,因为即使使用等于expectedList
的参数调用run()
,它也会被修改,因为它的当前值不再等于expectedList
。然而,这是它应该工作的方式,所以我想知道是否有方法让Mockito在调用方法时存储参数的快照,并根据这些值而不是最新的值对其进行验证。
使用Answer
检查方法调用时参数的值。如果值错误,您可以将AssertionError
丢到Answer
之内,或者您可以存储该值,并在最后进行断言。
对于不是mock
的对象,不能调用verify()
。这是你的意思吗?
Bar collaborator = mock(Bar.class);
Foo sut = spy(new Foo(collaborator));
verify(collaborator).run(expectedList);
谢谢,示例代码有一个错误,我纠正它。那不是我的问题。这是关于能够根据方法调用时的值验证参数,而不是最新的。 – 2012-01-31 23:34:23
为什么不尝试使用参数捕获获取期望列表的值,当它运行,然后你可以比较它。
ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class);
verify(collaborator).run(listCaptor.capture());
assertEquals(expectedList, argument.getValue());
如果你修改过的列表是同一个实例,那么argument.getValue()将返回'expectedList'实例,而不是副本,所以这和本质上是一样的,不是吗? – jhericks 2012-01-31 21:47:40
@Michael Wiles谢谢,但正如jhericks所提到的,ArgumentCaptor捕获了原始的List实例。 – 2012-01-31 23:31:07
对不起,迈克尔,我低估了你的答案,因为你的解决方案与OP的测试有完全相同的问题,正如jhericks所解释的那样。 – 2012-02-01 00:33:25
The answer of Dawood ibn Kareem为我工作,但我缺少一个例子,也是我用科特林和Mockito-Kotlin,所以我的解决办法是这样的:
class Foo(var mutable: String)
interface Bar {
fun run(foo: Foo)
}
@Test fun `validate mutable parameter at invocation`() {
val bar = mock<Bar>()
var valueAtInvocation: String? = null
whenever(bar.run(any())).then {
val foo = it.arguments.first() as Foo
valueAtInvocation = foo.mutable // Store mutable value as it was at the invocation
Unit // The answer
}
val foo = Foo(mutable = "first")
bar.run(foo)
valueAtInvocation isEqualTo "first"
foo.mutable = "second"
bar.run(foo)
valueAtInvocation isEqualTo "second"
}
valueAtInvocation
将在最后调用代表可变属性foo.mutable
的价值bar.run(foo)
。也应该可以在then {}
区块内做出断言。
是的,大卫是对的。由于Mockito API的制作方式,不可能使用相同的参数引用来验证多个调用。 EasyMock可以这样做,因为它在生产代码运行之前有一个期望阶段。无论如何,我不是使用'Answer',而是使用'ArgurmentCaptor'并在该列表的最后状态中写入一个或多个断言,即使用FEST-Assert' assertThat(captor.getValue())。contains(“A”,“B “).contains(”T“,”U“);' – Brice 2012-02-01 13:33:09
@Brice - 这与Michael Wiles的方法有什么不同? – 2012-02-01 20:28:13
它不是。这只是实现测试目的的一种不同方式。因为大多数时候你并不需要检查中间参数,而只是发生了一些相互作用和最终结果。虽然我必须说,如果汤姆有具体的要求,然后同意这不会帮助他,但在这种情况下,我会避免我的生产代码中的可变对象。感觉两个协作者和消息之间的消息应该永远是不可变的。 – Brice 2012-02-02 15:15:16