Ответ
Мой подход к unit-тестированию основан на том, что тесты — это неотъемлемая часть кода, обеспечивающая его надежность, поддерживаемость и безопасный рефакторинг.
Основные принципы:
-
Инструменты: Я использую стандартный пакет
testing
как основу. Для более удобных и читаемых проверок (assertions) предпочитаю библиотекуtestify/assert
илиtestify/require
. -
Table-Driven Tests (табличные тесты): Это идиоматичный для Go способ организации тестов. Он позволяет легко описывать множество тестовых случаев, включая пограничные значения, в компактном и читаемом виде.
import ( "testing" "github.com/stretchr/testify/assert" ) func TestCalculate(t *testing.T) { testCases := []struct { name string // Имя теста a, b int want int wantErr bool // Ожидаем ли ошибку }{ {"positive numbers", 2, 3, 5, false}, {"zero values", 0, 0, 0, false}, {"negative number", -5, 3, -2, false}, // Можно добавить кейс с ошибкой, если функция ее возвращает } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { got, err := Calculate(tc.a, tc.b) if tc.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) assert.Equal(t, tc.want, got) } }) } }
-
Что я тестирую в первую очередь:
- Критическая бизнес-логика: Функции, которые реализуют ключевые правила приложения.
- Сложные алгоритмы: Функции с нетривиальной логикой.
- Пограничные случаи: Нулевые значения, пустые строки, отрицательные числа, максимальные значения.
- Обработка ошибок: Проверяю, что функция корректно возвращает и обрабатывает ошибки.
-
Мокинг (Mocking) зависимостей: Для изоляции тестируемого кода от внешних зависимостей (базы данных, внешние API) я использую интерфейсы. В тестах я подменяю реальную реализацию на мок (mock-объект), который имитирует нужное поведение. Это можно делать вручную или с помощью библиотек вроде
gomock
илиtestify/mock
. -
Покрытие кода (Code Coverage): Я использую
go test -cover
для анализа покрытия. Я стремлюсь к показателю в 70-80% для важной логики, но отношусь к нему как к инструменту, а не цели. 100% покрытие тривиальных геттеров/сеттеров бесполезно, в то время как 80% покрытие критического модуля — это отличный результат. Главное — уверенность в корректности кода.