Вопрос по mocking, apache-httpclient-4.x, mockito, java – Mocking Apache HTTPClient с использованием Mockito

18

Я пытаюсь смоделировать Apache HttpClient Interface, чтобы смоделировать один из его методов, упомянутых ниже, чтобы вернуть заглушенный объект JSON в ответ.

HttpResponse response = defaultHttpClient.execute(postRequest); 

Может ли кто-нибудь подсказать, как этого добиться с помощью некоторого примера кода? Ваша помощь будет принята с благодарностью.

Спасибо

Ваш Ответ

4   ответа
1

используя PowerMockito, который также может легко издеваться над финальными / статическими методами, закрытыми методами и анонимными классами. Вот'Пример кода для насмешливого http-запроса. JSON_STRING_DATA - это любая строка, которую вы хотите получить из метода execute.

PowerMockito.mockStatic(DefaultHttpClient.class);
    HttpClient defaultHttpClientMocked =  PowerMockito.mock(DefaultHttpClient.class);        
    PowerMockito.when(defaultHttpClientMocked.execute(Mockito.any(HttpPost.class))).thenReturn(createMockedHTTPResponse(JSON_STRING_DATA));
Позволять'Сделайте ставку: через 3 года PowerMockito больше не будет в моде, и любые тесты, которые его используют, будут "наследие» тесты (вероятно, @Ignore 'd, или бремя, которое нужно поддерживать, или ваша команда будет пытаться уйти от него). Кто-нибудь, пожалуйста, ответьте мне в июле 2021 года, если я ошибаюсь, и я буду есть скромный пирог. Sridhar-Sarnobat
3

Вы можете посмотреть наHttpClientMockЯ написал это для внутреннего проекта, но позже решил открыть исходный код. Это позволяет вам определять ложное поведение с помощью свободного API, а затем проверять количество совершенных вызовов. Пример:

HttpClientMock httpClientMock = new 
HttpClientMock("http://localhost:8080");
httpClientMock.onGet("/login?user=john").doReturnJSON("{permission:1}");

httpClientMock.verify().get("/login?user=john").called();
Это выглядит очень хорошо, но как убедиться, что тестируемый класс использует вашHttpClientMock вместо ?HttpClients.createDefault() neXus
Ну, это может выглядеть очень по-разному между приложениями. В моих приложениях обычно у меня есть отдельная тестовая конфигурация, которая вставляет HttpClientMock в контекст приложения. Paweł Adamski
17

чтобы протестировать мой код с помощью Mockito и Apache HttpBuilder:

Тестируемый класс:

import java.io.BufferedReader;
import java.io.IOException;

import javax.ws.rs.core.Response.Status;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class StatusApiClient {
private static final Logger LOG = LoggerFactory.getLogger(StatusApiClient.class);

    private String targetUrl = "";
    private HttpClient client = null;
    HttpGet httpGet = null;

    public StatusApiClient(HttpClient client, HttpGet httpGet) {
        this.client = client;
        this.httpGet = httpGet;
    }

    public StatusApiClient(String targetUrl) {
        this.targetUrl = targetUrl;
        this.client = HttpClientBuilder.create().build();
        this.httpGet = new HttpGet(targetUrl);
    }

    public boolean getStatus() {
        BufferedReader rd = null;
        boolean status = false;
        try{
            LOG.debug("Requesting status: " + targetUrl);


            HttpResponse response = client.execute(httpGet);

            if(response.getStatusLine().getStatusCode() == Status.OK.getStatusCode()) {
                LOG.debug("Is online.");
                status = true;
            }

        } catch(Exception e) {
            LOG.error("Error getting the status", e);
        } finally {
            if (rd != null) {
                try{
                    rd.close();
                } catch (IOException ioe) {
                    LOG.error("Error while closing the Buffered Reader used for reading the status", ioe);
                }
            }   
        }

        return status;
    }
}

Тестовое задание:

import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.HttpHostConnectException;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

public class StatusApiClientTest extends Mockito {

    @Test
    public void should_return_true_if_the_status_api_works_properly() throws ClientProtocolException, IOException {
        //given:
        HttpClient httpClient = mock(HttpClient.class);
        HttpGet httpGet = mock(HttpGet.class);
        HttpResponse httpResponse = mock(HttpResponse.class);
        StatusLine statusLine = mock(StatusLine.class);

        //and:
        when(statusLine.getStatusCode()).thenReturn(200);
        when(httpResponse.getStatusLine()).thenReturn(statusLine);
        when(httpClient.execute(httpGet)).thenReturn(httpResponse);

        //and:
        StatusApiClient client = new StatusApiClient(httpClient, httpGet);

        //when:
        boolean status = client.getStatus();

        //then:
        Assert.assertTrue(status);
    }

    @Test
    public void should_return_false_if_status_api_do_not_respond() throws ClientProtocolException, IOException {
        //given:
        HttpClient httpClient = mock(HttpClient.class);
        HttpGet httpGet = mock(HttpGet.class);
        HttpResponse httpResponse = mock(HttpResponse.class);
        StatusLine statusLine = mock(StatusLine.class);

        //and:
        when(httpClient.execute(httpGet)).thenThrow(HttpHostConnectException.class);

        //and:
        StatusApiClient client = new StatusApiClient(httpClient, httpGet);

        //when:
        boolean status = client.getStatus();

        //then:
        Assert.assertFalse(status);
    }

}

Как вы думаете, ребята, мне нужно что-то улучшить? (Да, я знаю, комментарии. Это то, что я привел из своего фона Спока: D)

Это хорошо, но есть ли способ сделать это, когда ваши макеты не должны быть настолько специфичными для реализации? Например, чтобы тест продолжал работать, если мы переключили наш HTTP-клиент на другой интерфейс? В идеале, просто наблюдать за отправкой HTTP-запроса (и шпионить за такими вещами, как URL, заголовки, полезная нагрузка) и возможностью контролировать ответ, возвращающийся (и шпионить за такими вещами, как полезная нагрузка, заголовки)? Я'Я исходил из опыта тестирования JavaScript, где это шаблон - издевательство над бэкэндом на уровне браузера, а не на уровне библиотеки. oooyaya
5

В вашем классе юнит-теста вам нужно смоделировать:defaultHttpClient

@Mock
private HttpClient defaultHttpClient;

Затем вы говорите, mockito (например, в@Before метод) для создания ваших издевательств:

MockitoAnnotations.initMocks(YourTestClass);

Затем в своем методе испытаний вы определяете, чтоexecute() метод должен вернуть:

when(defaultHttpClient.execute(any()/* or wahtever you want here */)).thenReturn(stubbed JSON object);
В mockito вы можете смоделировать все: интерфейсы, абстрактные классы, обычные классы. В вашем случае, если вы хотите смоделировать поведение толькоexecute() метод, который вы можете издеваться надHttpClient интерфейс. Но если вы хотите сделать имитацию методов изDefaultHttpClient которые нет доступны вHttpClient Вы должны издеваться надDefaultHttpClient класс прямо. Flying Dumpling
Спасибо, это замечательно! Но я также должен был знать, должен ли я вместо этого насмехаться над DefaultHttpClient или HttpClient? Global Dictator
Благодарю. Очень полезно. Я'попробую и подтверду, работает ли он .. Global Dictator
Привет яЯ пытаюсь издеваться над следующим: Global Dictator

Похожие вопросы