Какие существуют подходы и популярные библиотеки для мокирования в Go?

Ответ

В Go существует два основных подхода к мокированию зависимостей в тестах, и для каждого есть свои популярные инструменты.

1. Кодогенерация (Code Generation)

Этот подход заключается в автоматической генерации мок-объектов на основе интерфейсов. Это предпочтительный способ для сложных интерфейсов, так как он обеспечивает строгую типизацию и избавляет от рутины.

  • golang/mock (gomock)

    • Описание: Официальная библиотека от Google. Использует утилиту mockgen для генерации моков из интерфейсов. Очень мощная и гибкая.
    • Плюсы: Строгая проверка типов, интеграция с testing.T, выразительный синтаксис для описания ожиданий (EXPECT()).
  • 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. Типобезопасность и надёжность, блядь, рулят.