Ответ
Моки (mock-объекты) — это объекты-заглушки, которые имитируют поведение реальных зависимостей (например, баз данных, внешних API, файловой системы) в контролируемой среде, такой как unit-тесты.
Основные цели использования моков:
- Изоляция: Тестирование компонента (unit) в отрыве от его внешних зависимостей. Это гарантирует, что тест проверяет только логику самого компонента.
- Предсказуемость и контроль: Возможность эмулировать любые сценарии поведения зависимости: успешный ответ, различные виды ошибок, задержки, пустые данные и т.д.
- Скорость выполнения тестов: Исключение медленных операций, таких как реальные сетевые запросы или работа с диском, что критически важно для CI/CD.
- Проверка взаимодействий: Моки позволяют проверить, что тестируемый код вызывает нужные методы зависимости с правильными параметрами и в правильном порядке.
Важно отличать Mocks от Stubs и Fakes:
- Stub (Стаб): Простая заглушка, которая возвращает заранее заданные данные. Не проверяет взаимодействия.
- Mock (Мок): «Умная» заглушка, которая не только возвращает данные, но и отслеживает вызовы к себе (сколько раз был вызван метод, с какими аргументами).
- Fake (Фейк): Более сложная реализация, которая имеет рабочую, но упрощенную бизнес-логику (например,
in-memory
база данных вместо настоящей).
Пример мока HTTP-клиента в Go:
// Интерфейс, который мы будем мокировать
type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}
// Структура мока
type MockHTTPClient struct {
DoFunc func(req *http.Request) (*http.Response, error)
}
// Реализация метода интерфейса для мока
func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error) {
// Вызываем переданную функцию, чтобы контролировать результат
return m.DoFunc(req)
}
// Пример использования в тесте
func TestMyService_FetchData(t *testing.T) {
// Создаем мок-клиент
mockClient := &MockHTTPClient{
DoFunc: func(req *http.Request) (*http.Response, error) {
// Проверяем, что URL правильный
if req.URL.String() != "http://example.com/data" {
t.Errorf("unexpected URL: %s", req.URL.String())
}
// Возвращаем заранее подготовленный ответ
jsonResponse := `{"key":"value"}`
body := ioutil.NopCloser(strings.NewReader(jsonResponse))
return &http.Response{StatusCode: 200, Body: body}, nil
},
}
// ... здесь код, который использует HTTPClient ...
// myService := NewMyService(mockClient)
// result, err := myService.FetchData()
}
Популярные библиотеки для генерации моков в Go: gomock
и testify/mock
.