简体   繁体   English

Mockito:InvalidUseOfMatchersException

[英]Mockito: InvalidUseOfMatchersException

I have a command line tool that performs a DNS check.我有一个执行 DNS 检查的命令行工具。 If the DNS check succeeds, the command proceeds with further tasks.如果 DNS 检查成功,该命令将继续执行其他任务。 I am trying to write unit tests for this using Mockito. Here's my code:我正在尝试使用 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
    }
}

I am using .netAddressFactory to mock a static implementation of the .netAddress class. Here's the code for the factory:我正在使用 .netAddressFactory 来模拟 .netAddress class 的.netAddress实现。这是工厂的代码:

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

Here's my unit test case:这是我的单元测试用例:

@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();
    }
}

Exception on running testPostDnsCheck() test:运行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"));

Any input on how to solve this?关于如何解决这个问题的任何意见?

The error message outlines the solution.错误消息概述了解决方案。 The line线

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

uses one raw value and one matcher, when it's required to use either all raw values or all matchers.当需要使用所有原始值或所有匹配器时,使用一个原始值和一个匹配器。 A correct version might read正确的版本可能会读

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

I had the same problem for a long time now, I often needed to mix Matchers and values and I never managed to do that with Mockito.... until recently !我有很长一段时间都遇到同样的问题,我经常需要混合匹配器和值,而我从未设法用 Mockito 做到这一点......直到最近! I put the solution here hoping it will help someone even if this post is quite old.我把解决方案放在这里,希望即使这篇文章很旧,它也会对某人有所帮助。

It is clearly not possible to use Matchers AND values together in Mockito, but what if there was a Matcher accepting to compare a variable ?显然不可能在 Mockito 中一起使用 Matchers AND 值,但是如果有一个 Matcher 接受比较变量呢? That would solve the problem... and in fact there is : eq这将解决问题......实际上有: eq

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

In this example 'metas' is an existing list of values在这个例子中,'metas' 是一个现有的值列表

It might help some one in the future: Mockito doesn't support mocking of 'final' methods (right now).它可能在未来对某些人有所帮助:Mockito 不支持模拟“最终”方法(现在)。 It gave me the same InvalidUseOfMatchersException .它给了我同样的InvalidUseOfMatchersException

The solution for me was to put the part of the method that didn't have to be 'final' in a separate, accessible and overridable method.对我来说,解决方案是将方法中不必是“最终”的部分放在一个单独的、可访问的和可覆盖的方法中。

Review the Mockito API for your use case.针对您的用例查看Mockito API

For my case, the exception was raised because I tried to mock a package-access method.就我而言,引发异常是因为我试图模拟package-access方法。 When I changed the method access level from package to protected the exception went away.当我将方法访问级别从package更改为protected ,异常消失了。 Eg inside below Java class,例如在 Java 类下面,

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

the method String getName(String id) has to be AT LEAST protected level so that the mocking mechanism (sub-classing) can work.方法String getName(String id)必须至少protected级别,以便模拟机制(子类)可以工作。

Inspite of using all the matchers, I was getting the same issue:尽管使用了所有匹配器,但我遇到了同样的问题:

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

It took me little while to figure this out that the method I was trying to mock was a static method of a class(say Xyz.class) which contains only static method and I forgot to write following line:我花了一点时间才弄清楚我试图模拟的方法是一个类的静态方法(比如 Xyz.class),它只包含静态方法,我忘了写以下行:

PowerMockito.mockStatic(Xyz.class);

May be it will help others as it may also be the cause of the issue.可能它会帮助其他人,因为它也可能是问题的原因。

May be helpful for somebody.可能对某人有帮助。 Mocked method must be of mocked class , created with mock(MyService.class)模拟方法必须属于mock(MyService.class),使用mock(MyService.class)创建

Another option is to use a captor: https://www.baeldung.com/mockito-argumentcaptor另一种选择是使用捕获器: 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");

Captors are especially useful if say one member of the object you want to capture could be a random ID and another is something you can validate against.如果说您要捕获的 object 中的一个成员可能是一个随机 ID,而另一个是您可以验证的东西,则捕获器特别有用。

Do not use Mockito.anyXXXX().不要使用 Mockito.anyXXXX()。 Directly pass the value to the method parameter of same type.直接将值传递给相同类型的方法参数。 Example:例子:

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;
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM