Java Mockito能否根据方法调用时的值验证参数?

Java Mockito能否根据方法调用时的值验证参数?,java,unit-testing,mockito,Java,Unit Testing,Mockito,我有一个Foo类是SUT,还有一个Bar类是它的合作者Foo调用run(列出值)并将“expectedList”作为参数。然后,Foo将向该列表添加更多元素,使其状态与调用run()时的状态不同。这是我的测试用例 @Test public void testFoo() { Bar collaborator = spy(new Bar()); Foo sut = new Foo(collaborator); verify(collaborator).run(expecte

我有一个
Foo
类是SUT,还有一个
Bar
类是它的合作者
Foo
调用
run(列出值)
并将“
expectedList
”作为参数。然后,
Foo
将向该
列表添加更多元素,使其状态与调用
run()
时的状态不同。这是我的测试用例

@Test
public void testFoo() {
    Bar collaborator = spy(new Bar()); 
    Foo sut = new Foo(collaborator);
    verify(collaborator).run(expectedList);
}

请注意,协作者实际上是间谍对象,而不是模拟对象。此测试用例将失败,因为即使调用
run()
时使用的参数等于
expectedList
,但该测试用例自以来已被修改,其当前值不再等于
expectedList
。然而,这是它应该工作的方式,所以我想知道是否有一种方法可以让Mockito在调用方法时存储参数的快照,并根据这些值而不是最新的值来验证它们。

您不能在非
mock
的对象上调用
verify()
。这就是你的意思吗

Bar collaborator = mock(Bar.class); 
Foo sut = spy(new Foo(collaborator));
verify(collaborator).run(expectedList);

不能对非
mock
对象调用
verify()
。这就是你的意思吗

Bar collaborator = mock(Bar.class); 
Foo sut = spy(new Foo(collaborator));
verify(collaborator).run(expectedList);

为什么不尝试使用参数捕获在运行时获取预期列表的值,然后进行比较呢

ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class);

verify(collaborator).run(listCaptor.capture());

assertEquals(expectedList, argument.getValue());
ArgumentCaptor listCaptor=ArgumentCaptor.forClass(List.class);
验证(协作者).run(listCaptor.capture());
assertEquals(expectedList,argument.getValue());

为什么不尝试使用参数捕获在运行预期列表时获取该列表的值,然后进行比较呢

ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class);

verify(collaborator).run(listCaptor.capture());

assertEquals(expectedList, argument.getValue());
ArgumentCaptor listCaptor=ArgumentCaptor.forClass(List.class);
验证(协作者).run(listCaptor.capture());
assertEquals(expectedList,argument.getValue());

调用方法时,使用
答案检查参数值。如果值错误,您可以在
应答
中抛出一个
断言错误
,也可以存储该值,并在最后执行断言

调用方法时,使用
答案
检查参数值。如果值错误,您可以在
应答
中抛出一个
断言错误
,也可以存储该值,并在最后执行断言

为我工作,但我缺少一个例子,我也使用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"
}
类Foo(变量可变:字符串)
接口条{
趣味跑(foo:foo)
}
@Test fun`validate mutable parameter at invocation`(){
val bar=mock()
var VALUeATIONATION:字符串?=null
无论何时(bar.run(any())。然后{
val foo=it.arguments.first()作为foo
valueAtInvocation=foo.mutable//按调用时的状态存储可变值
答案
}
val foo=foo(mutable=“first”)
酒吧跑步(foo)
职业价值观等同于“第一”
foo.mutable=“秒”
酒吧跑步(foo)
价值观职业等同于“第二”
}
valueatintervation
将表示上次调用
bar.run(foo)
时可变属性
foo.mutable
的值。也可以在
then{}
块中进行断言。

对我来说很有效,但我缺少一个示例,我也使用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"
}
类Foo(变量可变:字符串)
接口条{
趣味跑(foo:foo)
}
@Test fun`validate mutable parameter at invocation`(){
val bar=mock()
var VALUeATIONATION:字符串?=null
无论何时(bar.run(any())。然后{
val foo=it.arguments.first()作为foo
valueAtInvocation=foo.mutable//按调用时的状态存储可变值
答案
}
val foo=foo(mutable=“first”)
酒吧跑步(foo)
职业价值观等同于“第一”
foo.mutable=“秒”
酒吧跑步(foo)
价值观职业等同于“第二”
}

valueatintervation
将表示上次调用
bar.run(foo)
时可变属性
foo.mutable
的值。也可以在
then{}
块中进行断言。

如果修改的列表是同一个实例,则argument.getValue()将返回
expectedList
实例,而不是副本,因此这与他所做的基本相同,不是吗?@Michael Wiles谢谢,但正如jhericks提到的,ArgumentCaptor捕获原始列表实例。抱歉,Michael,我否决了你的答案,因为正如jhericks所解释的,你的解决方案与OP的测试问题完全相同。如果你修改的列表是同一个实例,则argument.getValue()将返回
expectedList
实例,而不是副本,所以这和他做的基本上是一样的,不是吗?@Michael Wiles谢谢,但正如jhericks提到的,ArgumentCaptor捕获了原始列表实例。抱歉,Michael,我否决了你的答案,因为你的解决方案与OP的测试问题完全相同,正如jhericks解释的。谢谢,示例代码有一个错误,我更正了它。但这不是我的问题。它是基于方法调用时参数的值而不是最近的值来验证参数的。谢谢,示例代码有一个错误,我更正了它。但这不是我的问题。这是关于能够根据方法调用时的值来验证参数,而不是最近的值。是的,David是对的。由于Mockito的API的编制方式,无法使用同一参数引用验证多个调用。EasyMock可以做到这一点,因为它在运行生产代码之前有一个期望阶段。无论如何,我使用
ArgurmentCaptor
而不是
答案,并在该列表的最终状态上编写一个或多个断言,即使用FEST Assert
assertThat(captor.getValue())包含(“A”、“B”)。