java – Mockito Capture在捕获时不维护捕获的列表

在Mockito中,我们遇到的情况是列表的捕获不会返回预期的结果.测试用例:

>我们将“Pip”添加到列表中
>我们捕获列表
>我们在列表中添加“Sok”.

在我们的断言中,我们只期望“Pip”在那里,但“Sok”也在那里.我们认为这是不正确的,因为在捕获时“Sok”不在列表中.

java.lang.AssertionError:
预计:[Pip]
实际:[Pip,Sok]

>有人有解决方案吗?
>这是Mockito中的错误还是功能?
>为什么Mockito保留对列表的引用而不复制
列表一个捕获时间?

以下是测试用例:

@RunWith(MockitoJUnitRunner.class)
public class CaptureTest {

    @Captor
    private ArgumentCaptor<List> listCapture;

    @Mock
    private ListPrinter listPrinter;

    private TestClass testClass;

    @Before
    public void setUp() {
        testClass = new TestClass(listPrinter);
    }

    @Test
    public void testCapture() {
        testClass.simulateFailSituation();
        verify(listPrinter).printList(listCapture.capture());
        // THIS FAILS: Expected:[Pip],  Actual:[Pip, Sok]
        assertEquals(Collections.singletonList("Pip"), listCapture.getValue());
    }

    public class TestClass {

        private List list = new ArrayList();
        private ListPrinter listPrinter;

        public TestClass(ListPrinter listPrinter) {
            this.listPrinter = listPrinter;
        }

        private void simulateFailSituation() {
            list.add("Pip");
            listPrinter.printList(list);
            list.add("Sok");
        }
    }

    public interface ListPrinter {
        void printList(List list);
    }
  }

解决方法:

这可能听起来像一个惊人的功能,但然后想一想:如果它正在复制,它应该停在哪里?您可能会捕获一些对其他对象有很多引用的对象,并且最终可能会对JVM实例中的几乎所有对象进行深层复制.

这将是一个严重的性能打击,所以我有点理解为什么.

因此,您可以选择两种方法:

>在适用的地方使用不可变对象.除了更容易测试之外,它还使代码更易于阅读和调试.
>在通话时立即测试值,而不是捕获参考值.对于void方法,您可以使用带有Answer< Void>的doAnswer方法,在那里进行测试或复制.顺便说一下,这是新的,见How to make mock to void methods with mockito.

我发现它比验证更强大.在您的情况下,doAnswer看起来像这样:

doAnswer(invocation -> {
    assertEquals(Collections.singletonList("Pip"), invocation.getArguments()[0]);
    return null;
}).when(listPrinter).printList(Matchers.anyList());
上一篇:java – Mockito验证一个方法在间谍之后调用onces虽然它永远不会调用


下一篇:java – 为Presenter类编写Mockito测试(Presenter First Pattern)