是否有针对varargs阵列的Mockito eq匹配器?

时间:2014-06-18 21:20:40

标签: java junit mockito

尝试将作为参数传递的数组匹配到接收varargs数组的方法时,我遇到了问题。

其他问题/答案中提到的anyVararg()匹配器并不适合我,因为我想确保提供的数组是我需要的数组。

我将问题简化为这个更易于理解和抽象问题的例子(我的真正问题是生产代码并具有业务逻辑,因此对于这个问题的目的而言会令人困惑):

@RunWith(MockitoJUnitRunner.class)
public class UnitTest {
    private Object[] objectArray;
    private List<Object> expected;
    private TestTarget target;

    @Before
    public void setUp() {
        objectArray = new Object[]{ new Object() };
        expected = Arrays.asList(new Object(), new Object());
        target = Mockito.spy(new TestTarget());
    }

    @Test
    public void testMakeList() { // this pass as eq works well with normal array
        doReturn(expected).when(target).toList(Mockito.eq(objectArray));
        Assert.assertEquals(expected, target.makeList(objectArray));
    }

    @Test
    public void testMakeList1() { // this one fails as eq is not working with varargs
        doReturn(expected).when(target).toList1(Mockito.eq(objectArray));
        Assert.assertEquals(expected, target.makeList1(objectArray));
    }

    @Test
    public void testMakeListWithAryEq() { // fails, aryEq is not working with varargs
        doReturn(expected).when(target).toList1(AdditionalMatchers.aryEq(objectArray));
        Assert.assertEquals(expected, target.makeList1(objectArray));
    }

    private class TestTarget {
        public List<Object> makeList(Object[] objects) {
            return toList(objects);
        }

        public List<Object> makeList1(Object[] objects) {
            return toList1(objects);
        }

        protected List<Object> toList(Object[] objs) {
            return null;  // Not implemented "Intentionally"
        }

        protected List<Object> toList1(Object... objs) {
            return null;  // Not implemented "Intentionally"
        }
    }
}

当我在类中运行测试用例时,第一个测试用例将通过而不是其他两个,既不使用eq也不使用aryEq。显示以下跟踪:

java.lang.AssertionError: expected:<[java.lang.Object@56d5e457, java.lang.Object@7482384a]> but was:<null>
    at org.junit.Assert.fail(Assert.java:88)
    at org.junit.Assert.failNotEquals(Assert.java:743)
    at org.junit.Assert.assertEquals(Assert.java:118)
    at org.junit.Assert.assertEquals(Assert.java:144)
    ...

这是因为eq匹配器不使用varargs数组,是否有替代此用例的eq匹配器?

2 个答案:

答案 0 :(得分:6)

好的,我认为这里的答案需要一个自定义构建的匹配器,可以在单元测试中实现,如下所示:

private class MyVarargMatcher extends ArgumentMatcher<Object[]> implements VarargMatcher {
    private Object[] expectedValues;

    MyVarargMatcher(Object... expectedValues) {
        this.expectedValues = expectedValues;
    }

    @Override
    public boolean matches(Object varargArgument) {
        return new EqualsBuilder()
        .append(expectedValues, varargArgument)
        .isEquals();
    }
}

然后,在testMakeList1()中将第一行更改为:

Mockito.doReturn(expected).when(target).toList1(Mockito.argThat(new MyVarargMatcher(objectArray)));

来源:
How to properly match varargs in Mockito
http://maciejmadej.blogspot.com/2011/11/capturing-varargs-argument-using-custom.html

答案 1 :(得分:0)

匹配varargs没问题。唯一的限制是您必须将每个单独的数组条目指定为匹配的参数。我已经更新了下面的代码以显示我的意思。我创建了第二个objectArray2来使点更清晰。所有测试均通过:

@RunWith(MockitoJUnitRunner.class)
public class UnitTest {
    private Object[] objectArray;
    private Object[] objectArray2;
    private List<Object> expected;
    private TestTarget target;
    private Object obj,obj2;

    @Before
    public void setUp() {
        obj = new Object();
        obj2 = new Object();
        objectArray = new Object[]{ obj };
        objectArray2 = new Object[]{ obj, obj2 };
        expected = Arrays.asList(new Object(), new Object());
        target = Mockito.spy(new TestTarget());
    }

    @Test
    public void testMakeList() { // this pass as eq works well with normal array
        doReturn(expected).when(target).toList(Mockito.eq(objectArray));
        Assert.assertEquals(expected, target.makeList(objectArray));
    }

    @Test
    public void testMakeList1() { // since objectArray has one entry you need to add one matching argument
        doReturn(expected).when(target).toList1(Mockito.eq(obj));
        Assert.assertEquals(expected, target.makeList1(objectArray));
    }

    @Test
    public void testMakeListWithAryEq() { // since objectArray2 has two entries you need to add two matching arguments
        doReturn(expected).when(target).toList1(Mockito.eq(obj),Mockito.eq(obj2));
        Assert.assertEquals(expected, target.makeList1(objectArray2));
    }

    private class TestTarget {
        public List<Object> makeList(Object[] objects) {
            return toList(objects);
        }

        public List<Object> makeList1(Object[] objects) {
            return toList1(objects);
        }

        protected List<Object> toList(Object[] objs) {
            return null;  // Not implemented "Intentionally"
        }

        protected List<Object> toList1(Object... objs) {
            return null;  // Not implemented "Intentionally"
        }
    }
}