如何正确匹配Mockito中的varargs

问题描述 投票:131回答:9

我一直试图使用Mockito模拟一个使用vararg参数的方法:

interface A {
  B b(int x, int y, C... c);
}

A a = mock(A.class);
B b = mock(B.class);

when(a.b(anyInt(), anyInt(), any(C[].class))).thenReturn(b);
assertEquals(b, a.b(1, 2));

这不起作用,但是如果我这样做:

when(a.b(anyInt(), anyInt())).thenReturn(b);
assertEquals(b, a.b(1, 2));

尽管我在删除方法时完全省略了varargs参数,但这仍然有效。

有线索吗?

java mocking variadic-functions mockito
9个回答
210
投票

Mockito 1.8.1介绍了anyVararg() matcher

when(a.b(anyInt(), anyInt(), Matchers.<String>anyVararg())).thenReturn(b);

另见历史:https://code.google.com/archive/p/mockito/issues/62

弃用后编辑新语法:

when(a.b(anyInt(), anyInt(), ArgumentMatchers.<String>any())).thenReturn(b);

29
投票

一个有点无法记录的功能:如果你想开发一个匹配vararg参数的自定义匹配器,你需要让它实现org.mockito.internal.matchers.VarargMatcher才能正常工作。它是一个空的标记界面,没有它,当使用你的Matcher调用varargs方法时,Mockito将无法正确地比较参数。

例如:

class MyVarargMatcher extends ArgumentMatcher<C[]> implements VarargMatcher {
    @Override public boolean matches(Object varargArgument) {
        return /* does it match? */ true;
    }
}

when(a.b(anyInt(), anyInt(), argThat(new MyVarargMatcher()))).thenReturn(b);

5
投票

基于Eli Levine的答案是一个更通用的解决方案:

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.mockito.ArgumentMatcher;
import org.mockito.internal.matchers.VarargMatcher;

import static org.mockito.Matchers.argThat;

public class VarArgMatcher<T> extends ArgumentMatcher<T[]> implements VarargMatcher {

    public static <T> T[] varArgThat(Matcher<T[]> hamcrestMatcher) {
        argThat(new VarArgMatcher(hamcrestMatcher));
        return null;
    }

    private final Matcher<T[]> hamcrestMatcher;

    private VarArgMatcher(Matcher<T[]> hamcrestMatcher) {
        this.hamcrestMatcher = hamcrestMatcher;
    }

    @Override
    public boolean matches(Object o) {
        return hamcrestMatcher.matches(o);
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("has varargs: ").appendDescriptionOf(hamcrestMatcher);
    }

}

然后你可以将它与hamcrest的数组匹配器一起使用:

verify(a).b(VarArgMatcher.varArgThat(
            org.hamcrest.collection.IsArrayContaining.hasItemInArray("Test")));

(显然静态导入会使这更具可读性。)


3
投票

我一直在使用Peter Westmacott答案中的代码,但是使用Mockito 2.2.15,您现在可以执行以下操作:

verify(a).method(100L, arg1, arg2, arg3)

其中arg1, arg2, arg3是varargs。


1
投票

以topchef的答案为基础,

对于2.0.31-beta,我不得不使用Mockito.anyVararg而不是Matchers.anyVararrg:

when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b);

0
投票

在我的例子中,我想捕获其参数的方法的签名是:

    public byte[] write(byte ... data) throws IOException;

在这种情况下,您应该显式转换为字节数组:

       when(spi.write((byte[])anyVararg())).thenReturn(someValue);

我正在使用mockito版本1.10.19


0
投票

你也可以遍历参数:

Object[] args = invocation.getArguments(); 
for( int argNo = 0; argNo < args.length; ++argNo) { 
    // ... do something with args[argNo] 
}

例如,检查他们的类型并适当地投射它们,添加到列表或其他什么。


0
投票

调整@topchef的答案,

Mockito.when(a.b(Mockito.anyInt(), Mockito.anyInt(), Mockito.any())).thenReturn(b);

根据Mockito 2.23.4的java文档,Mockito.any()“匹配任何东西,包括nulls和varargs。”


-1
投票

您可以通过传递ArgumentCaptor捕获然后使用“getAllValues”将varargs作为列表检索来完成此操作,请参阅:https://stackoverflow.com/a/55621731/11342928

© www.soinside.com 2019 - 2024. All rights reserved.