Java – mockito capture does not maintain a list of captures when capturing
In mockito, we encounter a situation where the capture of the list does not return the expected results Test case:
>We add pip to the list > we capture the list > we add Sok to the list
In our assertion, we only expect "PIP" to be there, but "Sok" is also there We think this is incorrect because "Sok" is not in the list at the time of capture
java. Lang. assertionerror: expected: [PIP] actual: [pip, Sok]
>Does anyone have a solution? > Is this an error in mockito or a function? > Why does mockito keep a reference to the list instead of copying the list for a capture time?
The following are test cases:
@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); } }
Solution
This may sound like an amazing feature, but then think: if it's copying, where should it stop? You may catch some objects that have many references to other objects, and eventually you may make deep copies of almost all objects in the JVM instance
This will be a serious performance hit, so I kind of understand why
Therefore, you can choose two methods:
>Use immutable objects where applicable In addition to being easier to test, it also makes the code easier to read and debug. > Test the value immediately during a call instead of capturing the reference value For void methods, you can use the doanswer method with answer < void >, where you can test or copy By the way, this is new. See how to make mock to void methods with mockito
I find it more powerful than verification In your case, doanswer looks like this:
doAnswer(invocation -> { assertEquals(Collections.singletonList("Pip"),invocation.getArguments()[0]); return null; }).when(listPrinter).printList(Matchers.anyList());