Mockito: InvalidUseOfMatchersException

我有一个命令行工具,执行 DNS 检查。如果 DNS 检查成功,则命令继续执行进一步的任务。我正在尝试使用 Mockito 为此编写单元测试。这是我的密码:

public class Command() {
// ....
void runCommand() {
// ..
dnsCheck(hostname, new InetAddressFactory());
// ..
// do other stuff after dnsCheck
}


void dnsCheck(String hostname, InetAddressFactory factory) {
// calls to verify hostname
}
}

我使用 InetAddressFactory 来模拟 InetAddress类的静态实现:

public class InetAddressFactory {
public InetAddress getByName(String host) throws UnknownHostException {
return InetAddress.getByName(host);
}
}

下面是我的单元测试用例:

@RunWith(MockitoJUnitRunner.class)
public class CmdTest {


// many functional tests for dnsCheck


// here's the piece of code that is failing
// in this test I want to test the rest of the code (i.e. after dnsCheck)
@Test
void testPostDnsCheck() {
final Cmd cmd = spy(new Cmd());


// this line does not work, and it throws the exception below:
// tried using (InetAddressFactory) anyObject()
doNothing().when(cmd).dnsCheck(HOST, any(InetAddressFactory.class));
cmd.runCommand();
}
}

运行 testPostDnsCheck()测试的异常:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 1 recorded.
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));

有人知道怎么解决这个问题吗?

284452 次浏览

错误消息概述了解决方案

doNothing().when(cmd).dnsCheck(HOST, any(InetAddressFactory.class))

当需要使用所有原始值或所有匹配器时,使用一个原始值和一个匹配器。正确的版本可能是

doNothing().when(cmd).dnsCheck(eq(HOST), any(InetAddressFactory.class))

很长一段时间我都有同样的问题,我经常需要将 Matcher 和价值观混合起来,但是我从来没有成功地将 Mockito 做到这一点... ..。直到最近! 我把解决方案放在这里,希望它能帮助某人,即使这个职位是相当古老的。

显然,在 Mockito 不可能同时使用 Matcher 和值,但如果有一个 Matcher 接受比较一个变量会怎样?这样问题就解决了,事实上就是 等式

when(recommendedAccessor.searchRecommendedHolidaysProduct(eq(metas), any(List.class), any(HotelsBoardBasisType.class), any(Config.class)))
.thenReturn(recommendedResults);

在这个示例中,“ meta”是一个现有的值列表

Mockito 不支持嘲笑“ final”方法(现在)。它给了我相同的 InvalidUseOfMatchersException

对我来说,解决方案是将方法中不必是“最终”的部分放在一个单独的、可访问的和可重写的方法中。

查看用例的 Mockito API

尽管使用了所有的火柴,我还是得到了同样的问题:

"org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
1 matchers expected, 3 recorded:"

我花了一点时间才弄明白,我试图模仿的方法是一个类的静态方法(比如 Xyz.class) ,它只包含静态方法,我忘记写下面这行:

PowerMockito.mockStatic(Xyz.class);

它可能会帮助其他人,因为它也可能是问题的起因。

对于我的例子,引发异常是因为我试图模拟 package-access方法。当我将方法访问级别从 package改为 protected时,异常消失了。例如在 Java 类下面,

public class Foo {
String getName(String id) {
return mMap.get(id);
}
}

方法 String getName(String id)必须是 至少 protected级,这样模仿机制(子类化)才能工作。

不要使用 Mockito.anyXXXX ()。直接将值传递给相同类型的方法参数。 例如:

A expected = new A(10);


String firstId = "10w";
String secondId = "20s";
String product = "Test";
String type = "type2";
Mockito.when(service.getTestData(firstId, secondId, product,type)).thenReturn(expected);


public class A{
int a ;
public A(int a) {
this.a = a;
}
}

可能对某些人有帮助。模拟的方法必须是 嘲笑班,用 mock(MyService.class)创建

另一种选择是使用捕获器: https://www.baeldung.com/mockito-argumentcaptor

// assume deliver takes two values
@Captor
ArgumentCaptor<String> address; // declare before function call.
Mockito.verify(platform).deliver(address.capture(), any());
String value = address.getValue();
assertEquals(address == "some@thing.com");

如果您想要捕获的对象的一个成员可能是随机 ID,而另一个成员是您可以验证的对象,那么捕获器特别有用。