Как вернуть разное значение в Mockito на основе атрибута параметра?

Класс, который я тестирую, получает клиентскую оболочку:

Проверенный класс (snippest)

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

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

Инициализация теста:

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

В exmaple я всегда возвращаю "100", но Request имеет атрибут id, и я хотел бы вернуть разные значения в client.get(Request) на основе значения request.getId().

Как я могу это сделать?

Ответ 1

Вы можете использовать ответы Mockito, поэтому вместо:

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

записи:

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

Ответ 2

Вы можете создать ArgumentMatcher, чтобы он соответствовал Request по идентификатору.

Таким образом, сопоставление аргументов будет выглядеть следующим образом:

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

Тогда вы можете использовать его как:

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

В противном случае использование Answer также будет работать, но использование ArgumentMatcher позволит вам сделать код более "декларативным".

Ответ 3

Чтобы сделать это правильно и с минимальным кодом, вы должны использовать выражение ArgumentMatcher, лямбда и не забыть выполнить нулевую проверку членов фильтров в ArgumentMatcher лямбда (особенно если у вас более одного макета с тем же ArgumentMatcher).

Индивидуальный сортировщик аргументов:

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

Использование:

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