One way could be to avoid being too restrictive on your arguments in order to provide all the expected results with only one thenReturn call.
For example let’s say that I want to mock this method:
public String foo(String firstArgument, Object obj) {
return "Something";
}
You could then mock it by providing as many results as you want like below:
// Mock the call of foo of any String to provide 3 results
when(mock.foo(anyString(), anyObject())).thenReturn("val1", "val2", "val3");
Calls to foo with any parameters will provide respectively “val1“, “val2“, then any subsequent calls will provide “val3“.
In case you do care about passed values but don’t want to depend on call sequence you can use thenAnswer to provide an answer that matches with the second argument like you currently do but with 3 different thenReturn.
Assuming that you have overridden the method equals(Object o).
when(mock.foo(anyString(), anyObject())).thenAnswer(
invocation -> {
Object argument = invocation.getArguments()[1];
if (argument.equals(new ARequest(1, "A"))) {
return new AResponse(1, "passed");
} else if (argument.equals(new ARequest(2, "2A"))) {
return new AResponse(2, "passed");
} else if (argument.equals(new BRequest(1, "B"))) {
return new BResponse(112, "passed");
}
throw new InvalidUseOfMatchersException(
String.format("Argument %s does not match", argument)
);
}
);
Or simply, using the methods anyString and eq as argument marchers.
Assuming that you have overridden the method equals(Object o).
when(service.foo(anyString(), eq(new ARequest(1, "A"))))
.thenReturn(new AResponse(1, "passed"));
when(service.foo(anyString(), eq(new ARequest(2, "2A"))))
.thenReturn(new AResponse(2, "passed"));
when(service.foo(anyString(), eq(new BRequest(1, "B"))))
.thenReturn(new BResponse(112, "passed"));