如何验证Mockito是否使用期望参数(java.util.List作为参数)调用方法

时间:2017-01-10 05:07:40

标签: java unit-testing mockito

您可以在下面看到WorkWithArrayList的示例类。此类有两种方法removeFirstThreeinsertDataremoveFirstThree方法获取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是相等的,即使我们删除了第一个元素,它们也将保持相等。我很感兴趣为什么这个测试失败了。

2 个答案:

答案 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(或者在发生时检测每个调用)。