Какие существуют подходы и популярные библиотеки для мокирования в 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, так как это повышает надежность тестов.