Ответ
В Go существует два основных подхода к мокированию зависимостей в тестах, и для каждого есть свои популярные инструменты.
1. Кодогенерация (Code Generation)
Этот подход заключается в автоматической генерации мок-объектов на основе интерфейсов. Это предпочтительный способ для сложных интерфейсов, так как он обеспечивает строгую типизацию и избавляет от рутины.
-
golang/mock(gomock)- Описание: Официальная библиотека от Google. Использует утилиту
mockgenдля генерации моков из интерфейсов. Очень мощная и гибкая. - Плюсы: Строгая проверка типов, интеграция с
testing.T, выразительный синтаксис для описания ожиданий (EXPECT()).
- Описание: Официальная библиотека от Google. Использует утилиту
-
vektra/mockery- Описание: Популярная альтернатива
gomock. Также генерирует моки на основе интерфейсов, но многие находят её проще в настройке и использовании. - Плюсы: Простая установка и конфигурация, генерирует код, который легко читать.
- Описание: Популярная альтернатива
2. Ручное мокирование с использованием библиотек
В этом случае вы самостоятельно создаете структуру-мок, которая реализует нужный интерфейс, а библиотека помогает управлять ожиданиями и проверками.
-
testify/mock- Описание: Самая популярная библиотека для этого подхода. Является частью пакета
testify. Не требует кодогенерации. - Плюсы: Простота, не нужен шаг кодогенерации, легко начать использовать.
-
Пример:
import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) // Мок-структура, реализующая интерфейс type MyMockedObject struct { mock.Mock } // Реализация метода интерфейса func (m *MyMockedObject) DoSomething(input int) (bool, error) { // .Called() регистрирует вызов и его аргументы args := m.Called(input) // .Get() позволяет вернуть заранее определенные значения return args.Bool(0), args.Error(1) } func TestSomething(t *testing.T) { // Создаем экземпляр мока testObj := new(MyMockedObject) // Настраиваем ожидание: при вызове DoSomething(123) // вернуть true и nil testObj.On("DoSomething", 123).Return(true, nil) // ... здесь код, который вызывает testObj.DoSomething(123) ... // Проверяем, что все ожидаемые вызовы были совершены testObj.AssertExpectations(t) }
- Описание: Самая популярная библиотека для этого подхода. Является частью пакета
Специализированные библиотеки
h2non/gockилиjarcoal/httpmock: Используются для мокирования HTTP-клиентов и ответов на внешние запросы. Это незаменимо при тестировании кода, который взаимодействует с внешними API.
Вывод:
- Для небольших проектов или простых интерфейсов отлично подходит
testify/mock. - Для крупных проектов с множеством сложных интерфейсов предпочтительнее использовать кодогенерацию с помощью
gomockилиmockery, так как это повышает надежность тестов.
Ответ 18+ 🔞
Да ты посмотри, какие распиздяйства творятся в мире тестирования на Go, блядь! Тут целых два лагеря, как на войне, нахуй. И у каждого свои пушки.
1. Кодогенерация, или "Давайте машина поработает, а мы погуляем"
Суть проста, как три рубля: ты пишешь интерфейс, а потом какая-то ёбаная утилита берёт и генерирует на его основе готовый мок. Сидишь такой, попиваешь чаёк, а код пишется сам. Красота, да?
-
golang/mock(он жеgomock)- Это типа наш Лев Толстой, официальный, блядь. От самих гугловских пацанов. Там есть утилита
mockgen, которая как волшебная палочка: навел на интерфейс — получил мок. - Чем хорош: Всё строго, по типам, никакого "авось". Можно красиво описывать ожидания через этот их
EXPECT(). Идеально для больших и серьёзных проектов, где любая хуйня может вылезти боком.
- Это типа наш Лев Толстой, официальный, блядь. От самих гугловских пацанов. Там есть утилита
-
vektra/mockery- А это типа Алексей Толстой, блядь. Тоже уважаемый, но народ говорит, что с ним попроще. Тоже генерит моки, но конфигурация у него поприятнее, и код на выходе читать не так тошно.
2. Ручное мокирование, или "Сам себе режиссёр, оператор и монтажёр"
Тут ты не ждёшь милостей от кодогенератора, а берёшь и пишешь мок своими руками. Библиотека только подсказывает, как удобнее ожидания прописать.
-
testify/mock- О, это звезда, блядь! Самая популярная мартышлюшка для таких дел. Часть большого пакета
testify. Никакой кодогенерации — просто создал структуру, встроилmock.Mock, и поехали. - Плюсы: Охуенно просто начать. Захотел — написал, захотел — удалил. Для мелких интерфейсов или быстрого прототипа — идеально.
-
Смотри, как это выглядит, блядь:
import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) // Вот наш рукотворный мок. Встроили mock.Mock — и он уже умеет кучу трюков. type MyMockedObject struct { mock.Mock } // Реализуем метод интерфейса. Всё по-честному. func (m *MyMockedObject) DoSomething(input int) (bool, error) { // .Called() — это магия. Он запоминает, что его позвали и с какими аргументами. args := m.Called(input) // А тут мы достаём из его памяти то, что сами же туда положили. return args.Bool(0), args.Error(1) } func TestSomething(t *testing.T) { // Родили мок. testObj := new(MyMockedObject) // Настраиваем сценарий: "Если вызовут DoSomething с числом 123, верни true и nil". testObj.On("DoSomething", 123).Return(true, nil) // ... а вот тут твой код, который должен как раз вызвать testObj.DoSomething(123) ... // И в конце, как строгий режиссёр: "Так, а все ли сцены, которые я задумал, были сыграны?" testObj.AssertExpectations(t) }
- О, это звезда, блядь! Самая популярная мартышлюшка для таких дел. Часть большого пакета
А ещё есть спецназ
h2non/gockилиjarcoal/httpmock: Это когда тебе нужно протестировать код, который лезет в интернет за данными. Эти библиотеки — как подставные актёры вместо реального API. Сказали им "на запрос по такому-то URL верни вот это" — и они вернут. Чтобы твои тесты не упёрлись в реальный сервер, который может в любой момент накрыться медным тазом.
Итог, ёпта:
- Если проект маленький или интерфейсы простые — бери
testify/mockи не парься. Быстро и сердито. - Если проект — это овердохуища строк кода с кучей сложных интерфейсов, то лучше довериться машине и взять
gomockилиmockery. Типобезопасность и надёжность, блядь, рулят.