Как смоделировать класс HttpClient, чтобы вернуть разные ответы - PullRequest
0 голосов
/ 04 апреля 2019

Как я могу заставить Mockito возвращать разные значения HttpEntity в ответ на разные URI?

Тест собирается сделать несколько HTTP-запросов (все они являются запросами POST) с mockHttpClient.

HttpEntity httpEntity = EntityBuilder.create().setText(response).build();
PowerMockito.when(response, "getEntity").thenReturn(httpEntity);

И сам тест спроектирован следующим образом:

CloseableHttpClient client = mockHttpClient(200, HTTP_ENTITY);
runTest();
Mockito.verify(client, Mockito.times(2)).execute(Mockito.any());

Для того, чтобы вышеуказанный тест возвратил разные сущности HTTP, я попробовал следующее:

CloseableHttpClient client = Mockito.mock(CloseableHttpClient.class);
    Mockito.when(client.execute(new HttpPost("http://127.0.0.1:8000/new/a"))).thenReturn(resp1);
    Mockito.when(client.execute(new HttpPost("http://127.0.0.1:8000/new/a/b"))).thenReturn(resp2);

Но яневозможно создать различные объекты http и получить в ответ на основе URI в запросе.

Ответы [ 2 ]

2 голосов
/ 04 апреля 2019

Перво-наперво, в этом случае Powermock не требуется. Вам не нужно издеваться над статическими методами, конструкторами или чем-то еще неприятным.

Я подготовил небольшой пример теста, который работает для меня из коробки с Mockito 2.23.4, и вы можете видеть, что утверждение isSameAs ("Проверяет, что фактическое значение совпадает с заданным, т.е. с использованием == сравнения. ") действительно проверяет, соответствует ли определенный вызов POST ранее смоделированному ответу:

public class CloseableHttpClientTest {
    private final CloseableHttpClient client = mock(CloseableHttpClient.class);

    @Test
    public void mockClient() throws IOException {
        // given
        CloseableHttpResponse resp1 = mock(CloseableHttpResponse.class);
        CloseableHttpResponse resp2 = mock(CloseableHttpResponse.class);
        HttpPost post1 = new HttpPost("http://127.0.0.1:8000/new/a");
        HttpPost post2 = new HttpPost("http://127.0.0.1:8000/new/a/b");
        when(client.execute(post1)).thenReturn(resp1);
        when(client.execute(post2)).thenReturn(resp2);

        // when
        CloseableHttpResponse returnedResp1 = client.execute(post1);
        CloseableHttpResponse returnedResp2 = client.execute(post2);

        // then
        assertThat(returnedResp1).isSameAs(resp1);
        assertThat(returnedResp2).isSameAs(resp2);
        verify(client).execute(post1);
        verify(client).execute(post2);
    }
}
0 голосов
/ 05 апреля 2019

Спасибо, мле. Ваш ответ помог мне понять, как лучше структурировать тест. Но в этом случае я пытаюсь изменить его без какой-либо реструктуризации.

Я думал, что выложу свой ответ здесь на тот случай, если кто-то другой его ищет.

Mockito.doAnswer(new Answer<CloseableHttpResponse>() {
  @Override
  public CloseableHttpResponse answer(InvocationOnMock invocation) {
    CloseableHttpResponse httpResponse = Mockito.mock(CloseableHttpResponse.class);

    // No change to status code based on endpoints
    Mockito.when(status.getStatusCode()).thenReturn(withResponseCode);
    Mockito.when(httpResponse.getStatusLine()).thenReturn(status);

    HttpEntity entity = Mockito.mock(HttpEntity.class);
    Object[] args = invocation.getArguments();
    String endpoint = ((HttpPost) args[0]).getURI().getPath();
    if (endpoint.contains("/a/b")) {
      entity = EntityBuilder.create().setText("something").build();
      Mockito.when(httpResponse.getEntity()).thenReturn(entity);
    } else {
      entity = EntityBuilder.create().setText("something else").build();
      Mockito.when(httpResponse.getEntity()).thenReturn(entity);
    }
    return httpResponse;
  }
}).when(client).execute(Mockito.any(HttpUriRequest.class)); 

Интеграционный тест не проверяет самого остального клиента, и мне не нужны ручки и несколько ложных клиентов для разных ответов. И вышеупомянутое помогает мне в возврате различных ответов на основе конечной точки, которая получает запросы.

...