您可以在下面看到WorkWithArrayList
的示例类。此类有两种方法removeFirstThree
和insertData
。 removeFirstThree
方法获取List
作为参数并修改它,并插入到数据库中。在for
循环中,我展示了这个修改,好像它正在删除List
的{{1}}的第一个元素,并在每次迭代时插入数据。
我想要实现的是验证Integer
方法的参数。但insertData
方法仅使用verify
声明进行检查。
verify(workWithArrayList).insertData(expected);
当我运行此测试时,我面临以下错误:
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) {
}
}
}
修改:如果我们查看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)
方法的javadoc,我们可以看到:
传递的参数使用Mockito.verify
方法进行比较。
但变量equals()
和actual
是相等的,即使我们删除了第一个元素,它们也将保持相等。我很感兴趣为什么这个测试失败了。
答案 0 :(得分:2)
除非我错过了一些非常重要的东西,否则你会混淆一些东西,从而使自己更难以测试。
你看,修改一个列表,把列表放在某个地方是两个不同的职责。因此,将两个方面强制转换为同一个类会使测试变得困难!
这里有一个更好的方法:单独关注。创建一个执行列表操作的类。可以在没有任何模拟的情况下测试该类! 你创建一个列表;把它给列表修改类;并检查回来的内容。只需断言!
然后,当您知道列表操作有效时,您只需要测试将数据库写入数据库的工作情况;并且你不关心实际写的列表是什么样的!
答案 1 :(得分:1)
Mockito在存储调用详细信息时不会克隆或复制对象,也不会采用任何类型的“快照”;值传入,Mockito复制引用。这意味着匹配真正的可变对象可能非常违反直觉。
@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);
}
由于这些可变数据,使用Mockito来演示正确的行为可能非常困难,而无需诉诸复制数据的Answer
(或者在发生时检测每个调用)。