Roee Gavirel
Roee Gavirel

Reputation: 19445

How to return different value in Mockito based on parameter attribute?

The class that I test receive a client wrapper:

The tested class (snippest)

private ClientWrapper cw
public Tested(ClientWrapper cw) {
    this.cw = cw;
}

public String get(Request request) {
    return cw.getClient().get(request);
}

The test initialization:

ClientWrapper cw = Mockito.mock(ClientWrapper.class);
Client client = Mockito.mock(Client.class);
Mockito.when(cw.getClient()).thenReturn(client);
//Here is where I want to alternate the return value:
Mockito.when(client.get(Mockito.any(Request.class))).thenReturn("100");

In the exmaple I always return "100", but the Request have an attribute id and I would like to return different values to client.get(Request) based on the request.getId() value.

How can I do it?

Upvotes: 21

Views: 40393

Answers (3)

John Montgomery
John Montgomery

Reputation: 9058

You could create an ArgumentMatcher to let you match the Request by id.

So the argument matcher would be like this:

import org.mockito.ArgumentMatcher;

public class IsRequestWithId implements ArgumentMatcher<Request> {
    private final int id;

    public IsRequestWithId(int id) {
        this.id = id;
    }

    @Override
    public boolean matches(Object arg) {
        Request request = (Request)arg;
        return id == request.getId();
    }
}

Then you could use it like:

Mockito.when(client.get(Mockito.argThat(new IsRequestWithId(1)))).thenReturn("100");
Mockito.when(client.get(Mockito.argThat(new IsRequestWithId(2)))).thenReturn("200");

Otherwise using an Answer would also work, but using an ArgumentMatcher lets you keep the code more "declarative".

Upvotes: 9

magiccrafter
magiccrafter

Reputation: 5474

In order to do it right and with minimal code you have to use the ArgumentMatcher, lambda expression & don't forget to do a null check on the filters members in the ArgumentMatcher lambda (especially if you have more than one mock with the same ArgumentMatcher).

Customized argument matcher:

private ArgumentMatcher<Request> matchRequestId(final String target) {
    return request -> request != null &&
            target.equals(request.getId());
}

Usage:

 given(client.get(argThat(matchRequestId("1")))).willReturn("100");
 given(client.get(argThat(matchRequestId("2")))).willReturn("200");

Upvotes: 9

Adam Siemion
Adam Siemion

Reputation: 16039

You can use Mockito's answers, so instead of:

Mockito.when(client.get(Mockito.any(Request.class))).thenReturn("100");

write:

Mockito.when(client.get(Mockito.any(Request.class)))
 .thenAnswer(new Answer() {
   Object answer(InvocationOnMock invocation) {
     Object[] args = invocation.getArguments();
     Object mock = invocation.getMock();
     return "called with arguments: " + args;
   }
});

Upvotes: 42

Related Questions