Reputation: 1396
Below you can see an example class of WorkWithArrayList
. This class has two methods removeFirstThree
and insertData
. removeFirstThree
method gets a List
as an argument and modifies it, and inserts into database. In for
loop I showed this modification as if it was removing first element of the List
of Integer
s and inserts data on every iteration.
The thing I want to realise is to verify arguments of insertData
method. But verify
method checking with only first verify(workWithArrayList).insertData(expected);
declaration.
package test;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
public class MockitoVerifyWithArrayListTest {
private WorkWithArrayList workWithArrayList;
private List<Integer> actual;
private List<Integer> expected;
@Before
public void setUp() throws Exception {
workWithArrayList = spy(new WorkWithArrayList());
actual = new ArrayList<>();
actual.add(1);
actual.add(2);
actual.add(3);
actual.add(4);
actual.add(5);
actual.add(6);
expected = new ArrayList<>();
expected.add(1);
expected.add(2);
expected.add(3);
expected.add(4);
expected.add(5);
expected.add(6);
}
@Test
public void test() throws Exception {
workWithArrayList.removeFirstThree(actual);
expected.remove(0);
verify(workWithArrayList).insertData(expected);
expected.remove(0);
verify(workWithArrayList).insertData(expected);
expected.remove(0);
verify(workWithArrayList).insertData(expected);
}
public class WorkWithArrayList {
public void removeFirstThree(List<Integer> integers) {
for (int i = 0; i < 3; i++) {
integers.remove(0);
insertData(integers);
}
}
public void insertData(List<Integer> integers) {
}
}
}
When I run this test I am facing with the following error:
Argument(s) are different! Wanted:
workWithArrayList.insertData(
[2, 3, 4, 5, 6]
);
-> at test.MockitoVerifyWithArrayListTest.test(MockitoVerifyWithArrayListTest.java:46)
Actual invocation has different arguments:
workWithArrayList.insertData(
[4, 5, 6]
);
-> at test.MockitoVerifyWithArrayListTest.test(MockitoVerifyWithArrayListTest.java:43)
Edit: If we look at javadoc of Mockito.verify
method, we can see this:
Arguments passed are compared using equals()
method.
But variables actual
and expected
are equal, and they will remain being equal even when we remove both's first element. I'm interested why this test fails then.
Upvotes: 1
Views: 843
Reputation: 140523
Unless I miss something really essential, you are mixing up things and thus making it harder for yourself to test things.
You see, modifying a list and putting that list somewhere are two different responsibilities. Therefore you forcing both aspects into the same class makes testing hard!
A better approach here: separate concerns. Create a class that does list manipulation. That class can probably be tested without any mocking! You create a list; give that to the list modify class; and check what comes back. Just asserts required!
And then, when you know that list manipulation works, you only need to test that writing a list to the DB works; and you don't care how the list to write actually looks like!
Upvotes: 2
Reputation: 95704
Mockito doesn't clone or copy the object when storing invocation details, or take any sort of "snapshot"; the value is passed in and Mockito copies the reference. This means that it can be very counter-intuitive to match a real mutable object.
@Test
public void test() throws Exception {
// expected: [1, 2, 3, 4, 5, 6]; actual: [1, 2, 3, 4, 5, 6];
workWithArrayList.removeFirstThree(actual);
// expected: [1, 2, 3, 4, 5, 6]; actual: [4, 5, 6]
// Mockito's invocation list:
// three calls to removeFirstThree(actual), where actual is [4, 5, 6],
// even though actual had different values during each of the calls!
expected.remove(0);
verify(workWithArrayList).insertData(expected);
expected.remove(0);
verify(workWithArrayList).insertData(expected);
expected.remove(0);
verify(workWithArrayList).insertData(expected);
}
Because of this mutable data, it may be very hard to use Mockito to demonstrate correct behavior without resorting to an Answer
that copies the data (or otherwise detects each of the calls as they happen).
Upvotes: 1