Java 使用InOrder验证更改了的List对象的方法调用
我有一个回调接口,它有一个接受Java 使用InOrder验证更改了的List对象的方法调用,java,mockito,Java,Mockito,我有一个回调接口,它有一个接受列表对象的方法。我想使用inoorder来验证回调方法的调用次数是否正确,调用顺序是否正确,参数是否正确 问题是Mockito似乎感到困惑,因为我正在将相同的List对象传递到方法中,并在调用之间对其进行修改。调用inoder.verify()时,我希望在执行该方法调用时验证列表对象的值 代码: public class Test { @Test public void test() { Callback callback = Moc
列表
对象的方法。我想使用inoorder
来验证回调方法的调用次数是否正确,调用顺序是否正确,参数是否正确
问题是Mockito似乎感到困惑,因为我正在将相同的List
对象传递到方法中,并在调用之间对其进行修改。调用inoder.verify()时,我希望在执行该方法调用时验证列表
对象的值
代码:
public class Test {
@Test
public void test() {
Callback callback = Mockito.mock(Callback.class);
InOrder inOrder = Mockito.inOrder(callback);
{
List<String> list = new ArrayList<String>(); //note: this List object is inaccessible from the unit test in my real use-case
callback.foo("name1", list);
list.add("value");
callback.foo("name2", list);
}
inOrder.verify(callback).foo("name1", Arrays.<String> asList()); //fails here
inOrder.verify(callback).foo("name2", Arrays.asList("value"));
}
interface Callback {
void foo(String name, List<String> list);
}
}
Argument(s) are different! Wanted:
callback.onFoo([]);
Actual invocation has different arguments:
callback.onFoo([value]);
将列表
对象的副本传递到每个回调方法调用中会使测试通过。但我不想每次调用该方法时都创建一个新的列表
我查看了可以传递到Mockito.mock()
中的MockSettings
对象,但没有看到任何有用的内容
和我的相似。但该解决方案并不验证传递到每个方法调用中的集合的内容——它只验证传递到其中的某个集合的事实(anyCollectionOf()
)。它验证最终结果,但不验证单个调用
似乎提供了一个潜在的解决方案。它使用ArgumentCaptor
捕获传递到方法中的对象。但是,当我使用它来验证第一个方法调用时,在对其进行了所有修改之后,它返回List
对象,因此测试失败。我需要它返回一个List
对象,其状态与List
对象在该精确调用时的状态匹配
ArgumentCaptor argument=ArgumentCaptor.forClass(List.class);
inoorder.verify(callback.foo(Mockito.eq(“name1”),argument.capture());
assertEquals(Arrays.asList(),argument.getValue())//失败:“预期:但是:
inoorder.verify(callback.foo(Mockito.eq(“name2”),argument.capture());
assertEquals(Arrays.asList(“value”)、argument.getValue();
如何在不牺牲任何粒度的情况下通过此测试?提供了一个解决方案
基本上,为该方法创建一个自定义的Answer
,并在每次调用该方法时存储一个List
参数的副本。然后,验证所有副本是否都是您期望的副本。这并不理想,但它可以工作
@Test
public void test() {
Callback callback = Mockito.mock(Callback.class);
final List<List<String>> listParameters = new ArrayList<List<String>>();
Mockito.doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) throws Throwable {
List<String> list = (List<String>) invocation.getArguments()[1];
listParameters.add(new ArrayList<String>(list));
return null;
}
}).when(callback).foo(Mockito.anyString(), Mockito.anyList());
{
List<String> list = new ArrayList<String>(); //note: this List object is inaccessible from the unit test in my real use-case
callback.foo("name1", list);
list.add("value");
callback.foo("name2", list);
}
InOrder inOrder = Mockito.inOrder(callback);
inOrder.verify(callback).foo(Mockito.eq("name1"), Mockito.anyList());
inOrder.verify(callback).foo(Mockito.eq("name2"), Mockito.anyList());
Assert.assertEquals(Arrays.asList(
Arrays.asList(),
Arrays.asList("value")
), listParameters);
}
@测试
公开无效测试(){
Callback Callback=Mockito.mock(Callback.class);
最终列表listParameters=new ArrayList();
Mockito.doAnswer(新答案(){
公共Void应答(invocationmock调用)抛出可丢弃的{
List=(List)invocation.getArguments()[1];
添加(新的ArrayList(list));
返回null;
}
}).when(callback).foo(Mockito.anyString(),Mockito.anyList());
{
List List=new ArrayList();//注意:在我的实际用例中,从单元测试中无法访问此列表对象
callback.foo(“name1”,list);
增加(“价值”);
callback.foo(“name2”,list);
}
inoorder inoorder=Mockito.inoorder(回调);
inoorder.verify(callback.foo(Mockito.eq(“name1”),Mockito.anyList());
inoorder.verify(callback.foo(Mockito.eq(“name2”),Mockito.anyList());
Assert.assertEquals(Arrays.asList(
Arrays.asList(),
Arrays.asList(“值”)
),列表参数);
}
提供了一个解决方案
基本上,为该方法创建一个自定义的Answer
,并在每次调用该方法时存储一个List
参数的副本。然后,验证所有副本是否都是您期望的副本。这并不理想,但它可以工作
@Test
public void test() {
Callback callback = Mockito.mock(Callback.class);
final List<List<String>> listParameters = new ArrayList<List<String>>();
Mockito.doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) throws Throwable {
List<String> list = (List<String>) invocation.getArguments()[1];
listParameters.add(new ArrayList<String>(list));
return null;
}
}).when(callback).foo(Mockito.anyString(), Mockito.anyList());
{
List<String> list = new ArrayList<String>(); //note: this List object is inaccessible from the unit test in my real use-case
callback.foo("name1", list);
list.add("value");
callback.foo("name2", list);
}
InOrder inOrder = Mockito.inOrder(callback);
inOrder.verify(callback).foo(Mockito.eq("name1"), Mockito.anyList());
inOrder.verify(callback).foo(Mockito.eq("name2"), Mockito.anyList());
Assert.assertEquals(Arrays.asList(
Arrays.asList(),
Arrays.asList("value")
), listParameters);
}
@测试
公开无效测试(){
Callback Callback=Mockito.mock(Callback.class);
最终列表listParameters=new ArrayList();
Mockito.doAnswer(新答案(){
公共Void应答(invocationmock调用)抛出可丢弃的{
List=(List)invocation.getArguments()[1];
添加(新的ArrayList(list));
返回null;
}
}).when(callback).foo(Mockito.anyString(),Mockito.anyList());
{
List List=new ArrayList();//注意:在我的实际用例中,从单元测试中无法访问此列表对象
callback.foo(“name1”,list);
增加(“价值”);
callback.foo(“name2”,list);
}
inoorder inoorder=Mockito.inoorder(回调);
inoorder.verify(callback.foo(Mockito.eq(“name1”),Mockito.anyList());
inoorder.verify(callback.foo(Mockito.eq(“name2”),Mockito.anyList());
Assert.assertEquals(Arrays.asList(
Arrays.asList(),
Arrays.asList(“值”)
),列表参数);
}
如果您打算在我建议的副本中使用我的anser,您可以在捕获功能中创建列表的副本。然后在验证阶段,您可以检查这些副本是否正确。谢谢@SpaceTrucker。这不理想,但它可以工作。如果您打算在我建议的副本中使用我的anser我,你可以在捕获功能中创建列表的副本。然后在验证阶段,你可以检查这些副本是否正确。谢谢@SpaceTrucker。不理想,但它可以工作。如果你说“不理想”“,你认为哪一个更好?@SpaceTrucker如果我的原始代码能够工作,那就更好了。”。这个解决方案冗长,读起来不好。如果你说“它不理想”,你认为什么更好?@SpaceTrucker如果我的原始代码有效,那会更好。该解决方案冗长,读起来不好。