Перейти к основному содержимому

Тестирование (testing)

Главное правило тестирования в Go: файлы с тестами должны называться название_файла_test.go и лежать в той же папке, что и тестируемый код.

1. Unit-тесты: Простейший пример

Предположим, у нас есть файл math.go с функцией:

func Add(a, b int) int {
return a + b
}

Создаем файл math_test.go:

package main

import "testing"

// Имя функции должно начинаться с Test и принимать *testing.T
func TestAdd(t *testing.T) {
result := Add(2, 3)
expected := 5

if result != expected {
// t.Errorf помечает тест как проваленный и выводит ошибку
t.Errorf("Ожидалось %d, получено %d", expected, result)
}
}

Чтобы запустить тест, в терминале введите: go test -v ./... (флаг -v показывает подробный вывод).

2. Табличное тестирование (Table-Driven Tests)

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

func TestAddTable(t *testing.T) {
// Таблица данных
tests := []struct {
name string
a, b int
expected int
}{
{"positive", 2, 3, 5},
{"negative", -1, -1, -2},
{"zero", 0, 0, 0},
}

for _, tt := range tests {
// t.Run создает "подтест" — удобно для отладки конкретного случая
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Ошибка в %s: ожидалось %d, получено %d", tt.name, tt.expected, result)
}
})
}
}

3. Как проверить, что функция паникует?

Иногда нам нужно убедиться, что код правильно реагирует на критическую ошибку (panic).

func TestDivideByZero(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("Функция должна была запаниковать, но не запаниковала")
}
}()

// Вызываем функцию, которая должна вызвать panic
// Например: Divide(10, 0)
}

4. Бенчмарки (Производительность)

Go позволяет измерять скорость выполнения кода с помощью тех же тестов. Функция должна начинаться с Benchmark.

func BenchmarkAdd(b *testing.B) {
// b.N — это число, которое Go подбирает сам, чтобы получить точный результат
for i := 0; i < b.N; i++ {
Add(1, 2)
}
}

Запуск: go test -bench=.

5. Зачем нам это? (Культура тестирования)

  1. Гарантия рефакторинга: Вы можете переписать внутренности функции Add, и если тесты проходят — вы ничего не сломали.
  2. Документация: Тесты показывают, как правильно использовать вашу функцию (какие аргументы подавать и что ожидать на выходе).
  3. CI/CD: Современные системы сборки не дадут вам выложить код в продакшн, если хотя бы один тест провален.

Золотые правила тестирования в Go:

  • Один тест — одна логическая проверка.
  • Используйте табличные тесты для проверки набора крайних случаев (edge cases).
  • Не тестируйте приватные методы напрямую. Если вам нужно протестировать приватную логику, значит, ваша функция делает слишком много — разбейте её на части.
  • Всегда проверяйте покрытие: go test -cover покажет, какой процент вашего кода реально покрыт тестами.