我有一个执行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"));
关于如何解决这个问题,有什么意见吗?
错误消息概述了解决方案。线路
doNothing().when(cmd).dnsCheck(HOST, any(InetAddressFactory.class))
当需要使用所有原始值或所有匹配器时,使用一个原始值和一个匹配器。正确的版本可能读取
doNothing().when(cmd).dnsCheck(eq(HOST), any(InetAddressFactory.class))
我有同样的问题很长一段时间了,我经常需要混合Matchers和值,而我从来没有用Mockito做到这一点。。。。直到最近!我把解决方案放在这里,希望它能帮助别人,即使这篇文章很旧。
很明显,在Mockito中不可能同时使用Matchers和值,但如果有Matcher接受比较变量呢?这将解决问题。。。事实上有:eq
when(recommendedAccessor.searchRecommendedHolidaysProduct(eq(metas), any(List.class), any(HotelsBoardBasisType.class), any(Config.class)))
.thenReturn(recommendedResults);
在本例中,"metas"是一个现有的值列表
这可能会在未来对某些人有所帮助:Mockito不支持对"final"方法的嘲讽(现在)。它给了我同样的InvalidUseOfMatchersException
。
对我来说,解决方案是将方法中不必是"final"的部分放在一个单独的、可访问的和可重写的方法中。
查看Mockito API以了解您的用例。
可能对某人有所帮助。模拟方法必须是模拟类,使用mock(MyService.class)
对于我的案例,由于我试图模拟package-access
方法,所以引发了异常。当我将方法访问级别从package
更改为protected
时,异常消失了。例如,在Java类、之下
public class Foo {
String getName(String id) {
return mMap.get(id);
}
}
方法CCD_ 8必须是至少CCD_。
尽管使用了所有的匹配器,我还是遇到了同样的问题:
"org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
1 matchers expected, 3 recorded:"
我花了很长时间才发现,我试图模拟的方法是一个类的静态方法(比如Xyz.class),它只包含静态方法,我忘记写下面一行:
PowerMockito.mockStatic(Xyz.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,而另一个成员是你可以验证的,那么捕捉器尤其有用。
不要使用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;
}
}