rasilvap
rasilvap

Reputation: 2149

Mockito InvalidUseOfMatchersException when I send matchers as Parameters

I'm working with mockito and I'm facing issues related with matchers parameters.

I'm getting this exception:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
-> at com.rccl.middleware.kidsclub.engine.services.RoomServiceTest.findBetweenMinAgeAndMaxAge_roomNot(RoomServiceTest.java:43)

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"));

For more info see javadoc for Matchers class.

Even though I'm using matchers in all the parameters I got this error message, I suppose that it's because I'm sending one matcher in roomService.findByAgebut this method is calling a second one findBetweenMinAgeAndMaxAge and internally there are another two parameters in the next call. I'm not pretty sure about the cause of the issue and how can I fix it.

This is my test:

import com.rccl.middleware.kidsclub.engine.mock.MockDTO;
import com.rccl.middleware.kidsclub.engine.repository.RoomRepository;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Optional;
import com.rccl.middleware.kidsclub.engine.repository.model.ShipRoom.Room;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;


@RunWith(MockitoJUnitRunner.class)
public class RoomServiceTest {

    @Mock
    private RoomRepository roomRepository;
    @Rule
    public final ExpectedException expectedException = ExpectedException.none();

    private RoomService roomService;

    @Before
    public void init() {
        this.roomService = new RoomService(roomRepository);
    }

    @Test()
    public void findBetweenMinAgeAndMaxAge_roomNot() {
        int numRoomDTO = 3;
        Optional<Room> room = Optional.ofNullable(MockDTO.buildRandomRoom(numRoomDTO));
        given(roomRepository.findBetweenMinAgeAndMaxAge(any(Integer.class), anyString())).willReturn(room);
        roomService.findByAge(any(Integer.class));
    }
}

This is the findByAge method:

public Optional<RoomDTO> findByAge(int childAge) {
        return roomRepository.findBetweenMinAgeAndMaxAge(childAge, DEFAULT_AGGREGATOR_ID)
                .map(room -> ObjectMapperUtils.map(room, RoomDTO.class));
    }

It is the helper in the MockDTO class

public static Room buildRandomRoom(int index) {
        return new Room(RandomStringUtils.randomAlphabetic(10),
                RandomStringUtils.randomAlphabetic(10),
                RandomStringUtils.randomAlphabetic(15),
                RandomUtils.nextInt(0, 10),
                RandomUtils.nextInt(11, 20));
    }

Upvotes: 1

Views: 1097

Answers (1)

GhostCat
GhostCat

Reputation: 140467

Here:

roomService.findByAge(any(Integer.class));

That is the call into your production code that your test makes to "trigger" some activity, which is then checked, via verifying some result, or that some mock was called as expected.

But: you can't (and should not) use that argument matcher here. Just go:

roomService.findByAge(42); // or whatever number makes sense there

In other words: you provide a "real" argument. One of which you "know" what should happen. Meaning: you invoke production code, and you pass specific "context" to that call. And based on your knowledge "when I pass 42, X should happen", you then verify "yes, X did happen".

The argument matcher is solely used when writing specifications for Mockito mock objects. Like: the argument matcher matches incoming arguments against your specification, to make some sort of decision.

Argument matchers do not magically know how to create a value to pass into a method. Their only purpose is to match incoming arguments against something. Sure, their signature is written in a way that allowed you to write your code like that. But that is necessary to use argument matchers conveniently in your mock specification. Matchers don't really return values, they only accept them.

Upvotes: 1

Related Questions