使用InOrder验证具有更改的List对象的方法调用

时间:2016-08-05 01:42:01

标签: java mockito

我有一个回调接口,它有一个接受List对象的方法。我想使用InOrder来验证回调方法是否以正确的顺序调用适当的次数,并使用正确的参数。

问题是Mockito似乎感到困惑,因为我将相同的List对象传递给方法并在调用之间修改它。当我调用InOrder.verify()时,我想在执行该方法调用时验证List对象的值

代码:

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]);

List对象的副本传递到每个回调方法调用中会使测试通过。但是,每次调用该方法时,我都不想创建新的List

我查看了您可以传递到MockSettings的{​​{1}}对象,但没有看到任何可能有用的内容。

This question与我的相似。但是该解决方案不会验证传递给每个方法调用的集合的内容 - 它只验证某些集合传递给它的事实(Mockito.mock())。它验证最终结果,但不验证单个调用

This answer似乎提供了一个潜在的解决方案。它使用anyCollectionOf()来捕获传递给方法的对象。但是当我使用它来验证第一个方法调用时,它会在对它进行所有修改后返回ArgumentCaptor对象 ,从而使测试失败。我需要它返回一个List对象,其状态与List对象的状态在该精确调用处匹配。

List

如何在不牺牲任何粒度的情况下通过此测试?

1 个答案:

答案 0 :(得分:0)

question that @SpaceTrucker linked to提供了解决方案。

基本上,为方法创建自定义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);
}