Расскажите об основных инструментах для юнит-тестирования в Go.

Ответ

В Go сильная культура тестирования, основанная на встроенных в язык инструментах.

  1. Пакет testing: Это основа всего. Он предоставляет базовые возможности для написания тестов, бенчмарков и примеров. Тестовые функции должны начинаться с Test, принимать *testing.T и находиться в файлах _test.go.

    func TestSum(t *testing.T) {
        result := Sum(2, 3)
        expected := 5
        if result != expected {
            t.Errorf("Sum(2, 3) = %d; ожидалось %d", result, expected)
        }
    }
  2. Команды go test: Встроенная утилита для запуска тестов. Ключевые флаги:

    • go test ./... — запустить все тесты в проекте.
    • go test -v — показать детальный вывод.
    • go test -cover — рассчитать и показать процент покрытия кода тестами.
    • go test -bench . — запустить бенчмарки.
  3. Пакет testify: Хотя стандартная библиотека мощная, testify делает тесты более читаемыми и лаконичными. Чаще всего используются:

    • testify/assert: Предоставляет функции для утверждений (например, assert.Equal(t, expected, actual)). Если проверка не проходит, она регистрирует ошибку, но продолжает выполнение теста.
    • testify/require: Аналогичен assert, но при неудачной проверке немедленно останавливает выполнение теста (t.FailNow()). Это полезно, когда дальнейшие шаги теста не имеют смысла.
    import "github.com/stretchr/testify/assert"
    
    func TestSumWithAssert(t *testing.T) {
        assert.Equal(t, 5, Sum(2, 3), "Сумма должна быть равна 5")
    }
  4. Табличные тесты (Table-Driven Tests): Это не инструмент, а популярный паттерн в Go, который позволяет проверить множество сценариев в одном тесте. Он отлично сочетается со стандартным пакетом testing.

    func TestSumTable(t *testing.T) {
        cases := []struct {
            name     string
            a, b     int
            expected int
        }{
            {"positive", 2, 3, 5},
            {"negative", -2, -3, -5},
            {"zero", 2, -2, 0},
        }
    
        for _, tc := range cases {
            t.Run(tc.name, func(t *testing.T) {
                assert.Equal(t, tc.expected, Sum(tc.a, tc.b))
            })
        }
    }