Ответ
Мокирование в Go — это ключевая техника для написания изолированных юнит-тестов. Его основная цель — заменить реальные зависимости (например, базу данных или внешний API) на контролируемые тестовые двойники (моки).
В Go это достигается преимущественно через интерфейсы.
Подходы к мокированию:
-
Ручное мокирование Простой способ, при котором вы вручную создаете структуру, реализующую нужный интерфейс. Подходит для простых интерфейсов.
// Интерфейс нашей зависимости type UserStorage interface { GetUser(id int) (string, error) } // Ручной мок type MockUserStorage struct { User string Error error } func (m *MockUserStorage) GetUser(id int) (string, error) { return m.User, m.Error } // Тест, использующий мок func TestUserService(t *testing.T) { mockDB := &MockUserStorage{User: "test_user", Error: nil} service := NewUserService(mockDB) // ... дальнейшее тестирование логики сервиса } -
Автоматическая генерация моков Для сложных интерфейсов ручное создание моков становится утомительным. Здесь помогают инструменты кодогенерации.
Популярные инструменты:
-
gomock(от Google): Официальный и очень мощный инструмент. Он генерирует моки из интерфейсов с помощью утилитыmockgen. Его особенность — строгий контроль вызовов черезcontroller.// Пример теста с gomock ctrl := gomock.NewController(t) defer ctrl.Finish() mockDB := NewMockUserStorage(ctrl) // Сгенерированный мок mockDB.EXPECT().GetUser(1).Return("test_user", nil).Times(1) service := NewUserService(mockDB) // ... -
testify/mock: Часть популярной библиотекиtestify. Более гибкий и менее строгий, чемgomock. Не требует обязательной кодогенерации (хотя отлично работает в паре сmockery), что делает его проще для старта. -
mockery: Утилита для генерации моков, которая отлично интегрируется сtestify/mock.
Ключевой вывод: Независимо от инструмента, основа хорошего мокирования в Go — это проектирование кода с использованием интерфейсов для отделения бизнес-логики от ее зависимостей.
Ответ 18+ 🔞
А, мокирование в Go, говоришь? Ну это ж святое дело, блядь! Это когда ты свою логику от всех этих баз данных и внешних апишек отвязываешь, чтобы тесты не превращались в ебаный цирк с конями, где всё падает из-за того, что какой-то сервис лег.
Вот смотри, основа всего этого шапито — интерфейсы. Без них нихуя не получится. Это как если бы ты пришел на стройку без лопаты — можешь ковырять землю руками, но заебёшься, блядь.
Как это, сука, делают?
-
Ручками, по-старинке Для простых штук — почему бы и нет. Написал структуру-заглушку, реализовал пару методов и поехали.
// Вот есть у нас какая-то хрень, которая пользователей ищет type UserStorage interface { GetUser(id int) (string, error) } // А вот наш рукожопый мок для неё type MockUserStorage struct { User string Error error } func (m *MockUserStorage) GetUser(id int) (string, error) { return m.User, m.Error // Просто отдаём то, что заранее всунули. Никаких сюрпризов, епта. } // И тест func TestUserService(t *testing.T) { mockDB := &MockUserStorage{User: "test_user", Error: nil} service := NewUserService(mockDB) // ... и дальше проверяем, что наш сервис не обосрался с такими данными }Всё просто, как три копейки. Но если интерфейс на два листа — писать такой мок замучаешься, волнение ебать.
-
Автоматом, как цивилизованные люди Вот для этого и придумали инструменты, чтобы не ебать себе мозг.
Инструменты на любой вкус и цвет
-
gomockот Гугла — это такой строгий дядька в очках. Официальный, мощный, но любит, чтобы всё было по правилам. Требует кодогенерации черезmockgen. Зато он следит, чтобы ты вызвал метод ровно столько раз, сколько сказал. Раз сказал —Times(1), а вызвал дважды? Получай ошибку, пидарас шерстяной!ctrl := gomock.NewController(t) defer ctrl.Finish() // Важно не забыть, а то он тебе в тестах мозг выест mockDB := NewMockUserStorage(ctrl) // Мок, сгенерированный автоматом // Вот тут магия: говорим, чего ждём mockDB.EXPECT().GetUser(1).Return("test_user", nil).Times(1) service := NewUserService(mockDB) // ... -
testify/mock— более расслабленный парень. Часть большой библиотекиtestify. Его можно и руками написать, но обычно его генерируют через... -
mockery— вот этот чувак как раз и наклепает тебе моков дляtestify/mockпо щелчку пальцев. Удобно, гибко, не так строго, как гугловский.
А главная мысль, которую ты должен вынести, как кот сука собака: чтобы всё это великолепие работало, нужно изначально писать код так, чтобы он зависел от интерфейсов, а не от конкретных структур. Тогда подсунуть мок вместо настоящей базы — раз плюнуть. Иначе будешь потом рефакторить всё, блядь, с горящими глазами и матом в голосе.