Как издеваться над http.Client Do методом

Я пытаюсь найти решение, чтобы написать тест и смоделировать HTTP-ответ. В моей функции, где я принимаю интерфейс:

type HttpClient interface {
    Do(req *http.Request) (*http.Response, error)
}

Я делаю http получить запрос с базовой аутентификацией

func GetOverview(client HttpClient, overview *Overview) (*Overview, error) {

    request, err := http.NewRequest("GET", fmt.Sprintf("%s:%s/api/overview", overview.Config.Url, overview.Config.Port), nil)
    if (err != nil) {
        log.Println(err)
    }
    request.SetBasicAuth(overview.Config.User, overview.Config.Password)
    resp, err := client.Do(request)

Как я могу издеваться над этим HttpClient? Я ищу макет библиотеки, например: https://github.com/h2non/gock но есть только макет для Get и Post

Может быть, я должен сделать это по-другому. Буду благодарен за совет

5 ответов

Решение

Любая структура с методом, совпадающим с сигнатурой в вашем интерфейсе, будет реализовывать интерфейс. Например, вы можете создать структуру ClientMock

type ClientMock struct {
}

с методом

func (c *ClientMock) Do(req *http.Request) (*http.Response, error) {
    return &http.Response{}, nil
}

Вы могли бы тогда ввести это ClientMock структурировать в ваш GetOverview FUNC. Вот пример на игровой площадке Go.

net/http/httptest Пакет ваш лучший друг:

// generate a test server so we can capture and inspect the request
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
    res.WriteHeader(scenario.expectedRespStatus)
    res.Write([]byte("body"))
}))
defer func() { testServer.Close() }()

req, err := http.NewRequest(http.MethodGet, testServer.URL, nil)
assert.NoError(t, err)

res, err := http.DefaultClient.Do(req)
assert.NoError(t, err)
assert.Equal(t, scenario.expectedRespStatus, res.StatusCode, "status code should match the expected response")

Вы должны создать структуру с методами, которые соответствуют интерфейсу. Мок обычно используются в целях тестирования, поэтому люди хотят иметь возможность подготовить возвращаемые значения макетов методов. Для этого мы создаем структуру с атрибутами func, соответствующими методам.

Как ваш интерфейс:

type HttpClient interface {
    Do(req *http.Request) (*http.Response, error)
}

Эквивалентный макет:

type MockClient struct {
    DoFunc func(req *http.Request) (*http.Response, error)
}

func (m *MockClient) Do(req *http.Request) (*http.Response, error) {
    if m.DoFunc != nil {
        return m.DoFunc(req)
    }
    return &http.Response{}, nil
}

Затем следующий шаг - написать несколько тестов. Пример тут.

Я знаю, что прошло немного времени, но я недавно написал кое-что, чтобы помочь с этим недавно.

Как правило, для макетирования HTTP-запросов я рекомендую запускать настоящий HTTP-сервер локально, поскольку в Go это легко сделать. https://golang.org/pkg/net/http/httptest/ - довольно стандартный способ сделать это (см. пример кода, приведенный в разделе Тип сервера).

Однако, выполнив много HTTP-макетов, я хотел кое-что сделать немного больше, например, хорошую библиотеку-макет: простая настройка ожиданий, проверка выполнения всех запросов и т. Д. Я обычно использовал https://godoc.org/github.com/stretchr/testify/mock для насмешек и желаемых функций, подобных этому.

Поэтому я написал https://github.com/dankinder/httpmock, который в основном объединяет оба.

Если вы используетеClientотhttpбиблиотеку, я бы предпочел использоватьRoundTripperсделать это.

Сначала вам следует определить RoundTripper

      type mockRoundTripper struct {
    response *http.Response
}

func (rt *mockRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
    return rt.response, nil
}

Ваш unittest-тест будет выглядеть так:

      func TestGetOverview(t *testing.T) {
    // Set up your response
    json := `{"code": 0, "message": "success"}`
    recorder := httptest.NewRecorder()
    recorder.Header().Add("Content-Type", "application/json")
    recorder.WriteString(json)
    expectedResponse := recorder.Result()

    // Create an HTTP client
    client := http.Client{Transport: &mockRoundTripper{expectedResponse}}

    // Call your function
    overview, err := yourlib.GetOverview(client, &yourlib.Overview{})
    ....
}

Вот простой пример:https://go.dev/play/p/wtamTRAhsZX .

Другие вопросы по тегам