我一直试图使用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参数,但这仍然有效。
任何线索?
答案 0 :(得分:207)
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);
答案 1 :(得分:29)
一个有点无法记录的功能:如果你想开发一个匹配vararg参数的自定义匹配器,你需要让它实现org.mockito.internal.matchers.VarargMatcher
才能正常工作。这是一个空的标记界面,没有它,Mockito在使用你的匹配器调用varargs方法时不能正确地比较参数。
例如:
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);
答案 2 :(得分: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 :(得分:3)
我一直在使用Peter Westmacott的答案,但是对于Mockito 2.2.15,您现在可以执行以下操作:
verify(a).method(100L, arg1, arg2, arg3)
其中arg1, arg2, arg3
是varargs。
答案 4 :(得分:1)
以topchef的答案为基础,
对于2.0.31-beta,我必须使用Mockito.anyVararg而不是Matchers.anyVararrg:
when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b);
答案 5 :(得分:0)
在我的情况下,我想捕获其参数的方法的签名是:
public byte[] write(byte ... data) throws IOException;
在这种情况下,您应该明确地转换为字节数组:
when(spi.write((byte[])anyVararg())).thenReturn(someValue);
我正在使用mockito版本1.10.19
答案 6 :(得分:0)
你也可以遍历参数:
Object[] args = invocation.getArguments();
for( int argNo = 0; argNo < args.length; ++argNo) {
// ... do something with args[argNo]
}
例如检查他们的类型并适当地投射它们,添加到列表或其他任何内容。
答案 7 :(得分:0)
适应@topchef的答案,
Mockito.when(a.b(Mockito.anyInt(), Mockito.anyInt(), Mockito.any())).thenReturn(b);
根据Mockito 2.23.4的Java文档,Mockito.any()“匹配任何内容,包括null和varargs。”
答案 8 :(得分:0)
由于其他答案有意义并使测试明显有效,我仍然建议进行测试,就好像该方法没有采用可变参数,而是采用常规的明确定义的参数。这有助于在覆盖方法与可能的模糊参数相关的情况下,例如 SLF4J 记录器:
测试:
jobLogger.info("{} finished: {} tasks processed with {} failures, took {}", jobName, count, errors, duration);
这有一堆覆盖和重要的方法是这样声明的
Logger.info(String, Object...)
验证:
verify(loggerMock).info(anyString(), anyString(), anyInt(), anyInt(), anyString());
证明上面的 errors
是整数而不是长整数的证明,因此以下不会运行:
verify(loggerMock).info(anyString(), anyString(), anyInt(), anyLong(), anyString());
因此您可以轻松地使用 when()
而不是 verify()
-stuff 来设置所需的返回值。
它可能显示了更多的意图并且更具可读性。也可以在此处使用捕获,并且通过这种方式更容易访问。
使用 Mockito 2.15 测试
答案 9 :(得分:-1)
您可以通过传递ArgumentCaptor捕获,然后使用“ getAllValues”将变量作为列表检索来完成此操作,请参见:https://stackoverflow.com/a/55621731/11342928