логотип PurpleSchool
логотип PurpleSchool

Использование mock в Golang

Автор

Олег Марков

Введение

Приветствую вас в этом увлекательном мире тестирования в Golang! Если вы хотите писать код, который не сломается при первом же изменении, и который всегда будет работать, как задумано, вам будет полезно узнать о таком инструменте, как mock. Mock в тестировании позволяет изолировать код от внешних зависимостей и сосредоточиться на тестировании именно того, что вам нужно. Смотрите дальше, и я покажу вам, как это работает в Golang, где инструмента mock просто незаменимы.

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

Давайте погрузимся глубже и рассмотрим, как использовать mock в Golang.

Основы Mock в Golang

Прежде чем мы углубимся в детали, стоит упомянуть, что Golang предоставляет большой набор встроенных функций для тестирования, но сам по себе язык не предусматривает стандартных средств для работы с mock. Поэтому мы будем использовать сторонние библиотеки, такие как gomock и testify. Эти библиотеки помогут нам реалистично и эффективно работать с mock.

Установка Gomock

Gomock - это одна из самых популярных библиотек для создания mock в Golang. Первым делом, давайте установим её. Вы можете сделать это командой:

go get github.com/golang/mock/gomock

Кроме того, вам нужно установить mockgen, генератор кода для Gomock:

GO111MODULE=off go get github.com/golang/mock/mockgen@v1.6.0

Теперь, когда у вас есть инструменты, давайте перейдем к возможностям и использованию mock в Golang.

Создание Mock-объектов с помощью Gomock

Gomock позволяет вам создать интерфейс, который вы хотите замокать, а затем генерировать код mock для этого интерфейса. Давайте посмотрим пример. Представим, у вас есть интерфейс Database, который вы хотите протестировать.

// Database представляет собой интерфейс с операцией сохранения
type Database interface {
    Save(id int, data string) error
}

Теперь мы создадим mock для этого интерфейса. Используя mockgen, вы можете сгенерировать mock следующим образом:

mockgen -source=your_source_file.go -destination=mock/mock_database.go -package=mock

Таким образом, мы создаем mock-объект, который будет имитировать поведение вашего интерфейса Database во время тестирования.

Использование Mock-объектов в тестах

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

package main

import (
    "github.com/golang/mock/gomock"
    "testing"
    "your_package/mock" // Путь к папке с вашим mock
)

func TestSaveData(t *testing.T) {
    // Создаем новый контроллер mock объектов; он управляет их жизненным циклом
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()

    // Создаем mock объекта Database
    db := mock.NewMockDatabase(ctrl)

    // Ожидаем, что Save будет вызван с определенными аргументами
    db.EXPECT().Save(1, "test_data").Return(nil)

    // Здесь ваш тестируемый код, который должен вызвать метод Save
    err := SaveData(db, 1, "test_data")
    if err != nil {
        t.Errorf("expected nil, got %v", err)
    }
}

// SaveData - функция для тестирования
func SaveData(db Database, id int, data string) error {
    return db.Save(id, data)
}

В этом примере mock будет проверять только вызов метода с ожидаемыми параметрами и возвращать заранее заданные значения, позволяя вам протестировать, как ваша функция взаимодействует с интерфейсом Database.

Расширенные возможности Mock

Mocking в Golang может быть использован не только для верификации вызовов методов, но и для возврата специфичных значений или симуляции отказов. Смотрите пример ниже, чтобы увидеть, как это можно реализовать.

// Ожидаем, что Save будет вызван и он вернет ошибку
db.EXPECT().Save(2, "bad_data").Return(errors.New("save failed"))

// Тестируем обработку ошибки
err := SaveData(db, 2, "bad_data")
if err == nil || err.Error() != "save failed" {
    t.Errorf("expected save failed error, got %v", err)
}

Таким образом, используя mock, вы можете тестировать любые аспекты поведения вашего кода.

Заключение

Теперь вы понимаете, какие преимущества дает использование mock при тестировании вашего кода в Golang. С помощью библиотеки Gomock вы можете создавать mock-объекты, которые помогут вам уменьшить зависимость вашего кода от внешних факторов и сосредоточиться на собственно тестируемом функционале. Надеюсь, этот гид помог вам овладеть основами использования mock в Golang.

Теперь, имея эти знания, вы сможете делать тесты более масштабными и надежными, улучшая качество вашего программного обеспечения. Не забывайте экспериментировать и применять полученные умения, создавая более стойкие и надежные системы!

Микросервисы gRPC в GolangСтрелочка вправо

Все гайды по Golang

Работа с YAML в GolangПреобразование типов в GolangКонвертация структур в JSON в GolangStrconv в GolangИспользование пакета SQLx для работы с базами данных в GolangРазбираемся с SQL в GolangРазделение строк с помощью функции split в GolangSort в GoПоиск и замена строк в Go - GolangИспользование пакета reflect в GolangРабота с PostgreSQL в GoPointers в GolangПарсинг в GoРабота со списками (list) в GolangПреобразование int в string в GolangРабота с числами с плавающей точкой в GolangРабота с полями в GolangИспользование enum в GolangОбработка JSON в GoЧтение и запись CSV-файлов в GolangРабота с cookie в GolangРегистры в GoКэширование данных в GolangПреобразование byte в string в GolangByte в GoИспользование bufio для работы с потоками данных в GolangДобавление данных и элементов (add) в Go
Логирование в Golang. Zap, Logrus, Loki, GrafanaРабота с Docker-контейнерами в GoИспользование pprof в GolangМеханизмы синхронизации в GolangРабота с пакетом S3 в GolangМониторинг Golang приложений с помощью PrometheusОптимизация проектов на GoПаттерны проектирования в GolangМиграции базы данных в GolangОркестрация контейнеров Go с Kubernetes + DockerGjGo Playground и компилятор GolangИспользование go mod init для создания модулей GolangРабота с переменными окружения (env) в GolangКоманда go build в GolangАвтоматизация Golang проектов — CI/CD с GitLab CI и JenkinsОтладка кода в GolangЧтение и использование конфигурации в приложениях на GolangКомпиляция в GolangКак развернуть Go-приложение на облаке AWSАутентификация в Golang
Сетевые протоколы в GoПеременные в GolangЗначения в GolangДженерик %T и его применение в GolangТипы данных в GolangИспользование tls в GolangИспользование tag в структурах GolangSwitch в GoСтроки в GolangРабота с потоками (stream) в GolangSelect в GoРуны в GoРабота с пакетом params в GolangКонвертация строк в числа в GolangNull, Nil, None, 0 в GoНаименования переменных, функций и структур в GoInt в GolangУстановка GolangЧтение и установка HTTP заголовков в GolangMethods в GolangGoLand — IDE для разработки на Golang от JetBrainsОбработка «not found» в GolangFloat в GolangФлаги командной строки в Go (Golang)Запуск внешних команд в GolangОбработка ошибок в GoИспользование defer в GolangЗначения default в GolangГенерация кода в GoФорматирование кода в GolangЧистая архитектура в GolangКаналы (channels) в GolangПолучение body из HTTP запроса в Golang
Открыть базу знаний