Ответ
Прямое тестирование внутренней логики чужого микросервиса — это антипаттерн. Это зона ответственности команды, которая его разрабатывает. Наша задача — тестировать взаимодействие с ним, то есть проверять, что наш сервис корректно отправляет запросы и обрабатывает ответы в соответствии с оговоренным контрактом (API).
Существует несколько подходов:
-
Интеграционные тесты с моками (заглушками) Это самый частый подход. Мы не используем реальный соседний сервис, а поднимаем его легковесную имитацию (мок) во время теста. В Go для этого отлично подходит пакет
net/http/httptest
.- Что мы проверяем:
- Наш сервис правильно формирует HTTP-запрос (URL, заголовки, тело).
- Наш сервис корректно парсит успешный ответ.
- Наш сервис правильно обрабатывает ошибки (например, 404 или 500).
Пример (тестируем наш API-клиент):
package main import ( "encoding/json" "net/http" "net/http/httptest" "testing" ) // Структура пользователя, которую мы ожидаем от сервиса B type User struct { ID int `json:"id"` Name string `json:"name"` } // Клиент для взаимодействия с сервисом B type APIClient struct { BaseURL string Client *http.Client } // Метод нашего клиента, который мы хотим протестировать func (c *APIClient) GetUser(id int) (*User, error) { // ... логика похода в сервис B // В данном примере она не важна, так как мы тестируем взаимодействие // с мок-сервером, который имитирует сервис B. return nil, nil // Реальная логика здесь не нужна для примера } func TestGetUserFromServiceB(t *testing.T) { // 1. Создаем тестовый сервер, который будет имитировать сервис B server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Проверяем, что наш клиент пришел по правильному URL if r.URL.Path != "/users/1" { t.Errorf("Expected to request '/users/1', got %s", r.URL.Path) } w.WriteHeader(http.StatusOK) // Отдаем заранее подготовленный ответ json.NewEncoder(w).Encode(User{ID: 1, Name: "Alice"}) })) defer server.Close() // 2. Создаем экземпляр нашего клиента, указывая ему адрес мок-сервера // В реальном коде здесь будет метод вроде NewAPIClient(server.URL) // client := NewAPIClient(server.URL) // 3. Выполняем запрос и проверяем результат // user, err := client.GetUser(1) // ... тут идут проверки (asserts), что user.Name == "Alice" и err == nil }
- Что мы проверяем:
-
Контрактные тесты Более продвинутый подход. Производитель (сервис, который предоставляет API) и потребитель (наш сервис) договариваются о "контракте". Контракт описывает структуру запросов и ответов. Тесты автоматически проверяют, что и производитель, и потребитель соответствуют этому контракту. Инструменты: Pact, Pact-Go.
-
End-to-End (E2E) тесты Эти тесты запускаются на полностью развернутом окружении (например,
staging
), где все микросервисы работают по-настоящему. Они проверяют сквозные пользовательские сценарии. Это самые дорогие и медленные тесты, но они единственные, кто проверяет систему в целом.
Вывод: Мы не пишем тесты для чужих сервисов, но мы обязаны писать тесты, которые проверяют корректность интеграции нашего сервиса с ними, в первую очередь через мокирование зависимостей.