我最近从mockito-core版本1.10.19升级到最新版本(5.5.0)。我注意到在验证带有varargs参数的方法调用时,行为发生了变化。
在旧版本中,我使用了一个带有以下签名的自定义匹配器:
private class CustomMatcher<T> extends ArgumentMatcher<T[]> implements VarargMatcher
然而,在最新版本中,由于ArgumentMatcher的变化,我不得不修改签名:
private class CustomMatcher<T> implements ArgumentMatcher<T[]>, Serializable
下面是我的代码的简化版本:
package com.mockito.varargs.test;
import org.mockito.ArgumentMatcher;
import org.mockito.Mockito;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Arrays;
import static org.mockito.ArgumentMatchers.*;
public class TestHelper {
private final DummyClient client = Mockito.mock(DummyClient.class);
public TestHelper() {
}
public void execute(String... tags) {
client.record("action", 42L, tags);
client.histogram("someAspect", 100L, "type:total", "type:cpu", "type:wait", "type:sql");
new Verifier().verifyTagsAre("tag1", "tag2", "tag3");
}
public class Verifier {
public void verifyTagsAre(final String... expectedTags) {
Mockito.verify(client).record(eq("action"), eq(42L),
argThat(new CustomMatcher<>(expectedTags)));
Mockito.verify(client, Mockito.times(3)).histogram(eq("someAspect"), anyLong(),
argThat(new CustomAnyVarargMatcher<>(
new CustomMatcher<>("type:total", expectedTags),
new CustomMatcher<>("type:cpu", expectedTags),
new CustomMatcher<>("type:wait", expectedTags),
new CustomMatcher<>("type:sql", expectedTags)
)));
Mockito.verifyNoMoreInteractions(client);
}
}
private class CustomMatcher<T> implements ArgumentMatcher<T[]>, Serializable {
private T[] expectedValues;
CustomMatcher(T... expectedValues) {
this.expectedValues = expectedValues;
}
CustomMatcher(T t, T... expectedValues) {
T[] values = (T[]) Array.newInstance(t.getClass(), expectedValues.length + 1);
System.arraycopy(expectedValues, 0, values, 1, expectedValues.length);
values[0] = t;
this.expectedValues = values;
}
@Override
public boolean matches(T[] args) {
return Arrays.equals(expectedValues, args);
}
@Override
public String toString() {
return Arrays.toString(expectedValues);
}
}
private class CustomAnyVarargMatcher<T> implements ArgumentMatcher<T>, Serializable {
private ArgumentMatcher<T>[] matchers;
CustomAnyVarargMatcher(ArgumentMatcher<T>... matchers) {
this.matchers = matchers;
}
@Override
public boolean matches(T args) {
for (ArgumentMatcher<T> matcher : matchers) {
if (matcher.matches(args))
return true;
}
return false;
}
@Override
public String toString() {
return Arrays.toString(matchers);
}
}
interface DummyClient {
void record(String action, long value, String... tags);
void histogram(String aspect, long value, String... tags);
}
public static void main(String[] args) {
new TestHelper().execute("tag1", "tag2", "tag3");
}
}
当验证失败时,我得到这个错误:
Exception in thread "main" Argument(s) are different! Wanted:
dummyClient.record(
"action",
42L,
[tag1, tag2, tag3]
);
-> at com.mockito.varargs.test.TestHelper$Verifier.verifyTagsAre(TestHelper.java:26)
Actual invocations have different arguments:
dummyClient.record(
"action",
42L,
"tag1",
"tag2",
"tag3"
);
我希望预期的输出与实际的调用匹配,就像在1.10.19版中一样。有没有办法在最新版本中做到这一点?或者有没有一种方法可以在Mockito中将varargs作为数组进行比较,如果数组相等,则验证通过?
1条答案
按热度按时间ttcibm8c1#
你应该能够使用
AdditionalMatchers
,不需要自定义匹配器:参见GitHub issues mockito#1593和mockito#2835,特别是关于
argThat
的部分:argThat()
行为变化重大变化:
MockitoHamcrest
中的所有方法(如argThat()
)在传递给varargs参数时的行为都发生了变化。在Mockito v5之前,这些匹配器将匹配varargs参数中的每个元素,匹配任何数量的元素0. n。从Mockito v5开始,这些匹配器在传递给varargs参数时,将匹配传递给varargs参数的单个值的调用。要匹配传递给varargs参数的任意数量的值,请将use和varargs数组类型传递给argThat
。例如,给定String...
varargs参数,用途:argThat(isA(String[].class), String[].class)
。而且我希望代码只是问题的一个例子,因为没有真实的代码被测试。您有一个Mockito模拟对象,您在其上调用方法,然后验证该方法已被调用。我甚至不确定这个测试是否有效-
histogram
方法只被调用了一次,但是验证器检查了times(3)
(参数类型实际上并不匹配:expectedTags
永远不会传递给histogram
)。