在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());