Java 如何在 Mockito 中正确匹配可变参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2631596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to properly match varargs in Mockito
提问by qualidafial
I've been trying to get to mock a method with vararg parameters using Mockito:
我一直在尝试使用 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));
This doesn't work, however if I do this instead:
这不起作用,但是如果我这样做:
when(a.b(anyInt(), anyInt())).thenReturn(b);
assertEquals(b, a.b(1, 2));
This works, despite that I have completely omitted the varargs argument when stubbing the method.
这有效,尽管我在存根方法时完全省略了 varargs 参数。
Any clues?
有什么线索吗?
采纳答案by topchef
Mockito 1.8.1 introduced anyVararg() matcher:
Mockito 1.8.1 引入了anyVararg() 匹配器:
when(a.b(anyInt(), anyInt(), Matchers.<String>anyVararg())).thenReturn(b);
Also see history for this: https://code.google.com/archive/p/mockito/issues/62
另请参阅历史记录:https: //code.google.com/archive/p/mockito/issues/62
Editnew syntax after deprecation:
弃用后编辑新语法:
when(a.b(anyInt(), anyInt(), ArgumentMatchers.<String>any())).thenReturn(b);
回答by Eli Levine
A somewhat undocumented feature: If you want to develop a custom Matcher that matches vararg arguments you need to have it implement org.mockito.internal.matchers.VarargMatcher
for it to work correctly. It's an empty marker interface, without which Mockito will not correctly compare arguments when invoking a method with varargs using your Matcher.
一个有点未记录的功能:如果你想开发一个匹配 vararg 参数的自定义匹配器,你需要实现org.mockito.internal.matchers.VarargMatcher
它才能正常工作。它是一个空的标记接口,没有它 Mockito 在使用 Matcher 调用带有可变参数的方法时将无法正确比较参数。
For example:
例如:
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);
回答by Peter Westmacott
Building on Eli Levine's answer here is a more generic solution:
以 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);
}
}
Then you can use it with hamcrest's array matchers thus:
然后你可以将它与 hamcrest 的数组匹配器一起使用,因此:
verify(a).b(VarArgMatcher.varArgThat(
org.hamcrest.collection.IsArrayContaining.hasItemInArray("Test")));
(Obviously static imports will render this more readable.)
(显然,静态导入将使这更具可读性。)
回答by NPike
Building on topchef's answer,
以 topchef 的回答为基础,
For 2.0.31-beta I had to use Mockito.anyVararg instead of Matchers.anyVararrg:
对于 2.0.31-beta,我不得不使用 Mockito.anyVararg 而不是 Matchers.anyVararrg:
when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b);
回答by Seyed Jalal Hosseini
In my case the signature of the method that I want to capture its argument is:
在我的情况下,我想捕获其参数的方法的签名是:
public byte[] write(byte ... data) throws IOException;
In this case you should cast to byte arrayexplicitly:
在这种情况下,您应该显式转换为字节数组:
when(spi.write((byte[])anyVararg())).thenReturn(someValue);
I'm using mockito version 1.10.19
我正在使用 mockito 版本 1.10.19
回答by Mark
I have been using the code in Peter Westmacott's answer however with Mockito 2.2.15 you can now do the following:
我一直在使用 Peter Westmacott 的答案中的代码,但是在 Mockito 2.2.15 中,您现在可以执行以下操作:
verify(a).method(100L, arg1, arg2, arg3)
verify(a).method(100L, arg1, arg2, arg3)
where arg1, arg2, arg3
are varargs.
arg1, arg2, arg3
可变参数在哪里。
回答by Richard Whitehead
You can also loop over the arguments:
您还可以遍历参数:
Object[] args = invocation.getArguments();
for( int argNo = 0; argNo < args.length; ++argNo) {
// ... do something with args[argNo]
}
for example check their types and cast them appropriately, add to a list or whatever.
例如检查它们的类型并适当地转换它们,添加到列表或其他任何东西。
回答by Craig
Adapting the answer from @topchef,
改编@topchef的答案,
Mockito.when(a.b(Mockito.anyInt(), Mockito.anyInt(), Mockito.any())).thenReturn(b);
Per the java docs for Mockito 2.23.4, Mockito.any() "Matches anything, including nulls and varargs."
根据 Mockito 2.23.4 的 java 文档,Mockito.any()“匹配任何内容,包括空值和可变参数。”
回答by Clarke Lacher
You can accomplish this by passing an ArgumentCaptor capture and then retrieving the varargs as a list using "getAllValues", see: https://stackoverflow.com/a/55621731/11342928
您可以通过传递 ArgumentCaptor 捕获,然后使用“getAllValues”检索可变参数作为列表来完成此操作,请参阅:https://stackoverflow.com/a/55621731/11342928