Mockito: InvalidUseOfMatchersException
Asked Answered
D

9

192

I have a command line tool that performs a DNS check. If the DNS check succeeds, the command proceeds with further tasks. I am trying to write unit tests for this using Mockito. Here's my code:

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 InetAddressFactory to mock a static implementation of the InetAddress class. Here's the code for the factory:

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:

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?

Decollate answered 13/2, 2013 at 2:56 Comment(0)
G
379

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))
Glimmer answered 13/2, 2013 at 3:3 Comment(2)
But eq() needs two parameters.Successful
what if it is Mockito.<String>anyList()?Mothball
P
46

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 ! 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 ? That would solve the problem... and in fact there is : 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

Peccadillo answered 1/6, 2015 at 12:55 Comment(3)
Awesome. org.mockito.Mockito.eq()Rosio
the proper import is now org.mockito.ArgumentMatchers.eq()Peccadillo
So grateful for this tip. Thanks sam!Claybourne
S
22

It might help some one in the future: Mockito doesn't support mocking of 'final' methods (right now). It gave me the same 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.

Sophisticated answered 26/1, 2017 at 13:40 Comment(1)
This helped in figuring out why my kotlin code would give me error, cuz all methods in kotlin are final!Obeah
F
3

May be helpful for somebody. Mocked method must be of mocked class, created with mock(MyService.class)

Fernferna answered 25/1, 2021 at 11:22 Comment(1)
this is actually a valid point, as I just stumbled over this issue when discovering that I tried to invoke when() on a real service in my IT and it was no mock after all;=)Isologous
A
2

For my case, the exception was raised because I tried to mock a package-access method. When I changed the method access level from package to protected the exception went away. E.g. inside below Java class,

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.

Ailee answered 1/8, 2019 at 5:36 Comment(0)
G
0

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:

PowerMockito.mockStatic(Xyz.class);

May be it will help others as it may also be the cause of the issue.

Glossal answered 22/6, 2018 at 9:7 Comment(0)
T
0

Another option is to use a captor: 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 == "[email protected]");

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.

Technical answered 14/3, 2022 at 17:35 Comment(0)
C
0

Here is the correct answer:

  1. See that you are not running using SpringRunner under RunWith annotation. Instead use @RunWith(value = MockitoJUnitRunner.class)

  2. Change all @MockBean to @Mock

  3. The class on which test has to be performed should not be @Autowiere, instead it should be @InjectMocks

  4. See that all the private members of class on which you are running the methods are initlized using ReflectionUtil: Eg.
    ReflectionTestUtils.setField(manualRiskCasePipeline, "salesForceServiceClient", salesForceServiceClient);

  5. Also, Dont use isNull as return of a when().thenReturn(isNull) this will cause argumentMismatch, instead do: when().thenReturn(null);

Callao answered 6/1 at 20:58 Comment(0)
A
-1

Do not use 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;
   }
}
Aesthetically answered 15/10, 2020 at 15:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.