Какие существуют подходы и инструменты для тестирования в Go?

Ответ

В Go имеется мощная встроенная поддержка для тестирования, реализованная через стандартный пакет testing и инструментарий go test. Тесты принято располагать в тех же пакетах, что и тестируемый код, в файлах с суффиксом _test.go.

Основные виды тестов в стандартной библиотеке:

  1. Юнит-тесты (Test functions): Проверяют корректность работы отдельных функций. Имя тестовой функции должно начинаться с Test.

    func TestSum(t *testing.T) {
        got := Sum(2, 3)
        want := 5
        if got != want {
            t.Errorf("Sum(2, 3) = %d; want %d", got, want)
        }
    }
  2. Табличные тесты (Table-Driven Tests): Эффективный способ проверить функцию на множестве различных входных данных и ожидаемых результатов.

    func TestSum(t *testing.T) {
        cases := []struct {
            name string
            a, b, want int
        }{
            {"positive numbers", 1, 2, 3},
            {"zeroes", 0, 0, 0},
            {"negative and positive", -1, 1, 0},
        }
    
        for _, tc := range cases {
            t.Run(tc.name, func(t *testing.T) {
                got := Sum(tc.a, tc.b)
                if got != tc.want {
                    t.Errorf("got %d, want %d", got, tc.want)
                }
            })
        }
    }
  3. Тесты производительности (Benchmarks): Измеряют производительность кода. Имя функции должно начинаться с Benchmark.

    func BenchmarkSum(b *testing.B) {
        for i := 0; i < b.N; i++ {
            Sum(1, 2)
        }
    }
  4. Фаззинг-тесты (Fuzzing): Начиная с Go 1.18, позволяют автоматически генерировать входные данные для поиска пограничных случаев и уязвимостей. Имя функции начинается с Fuzz.

    func FuzzSum(f *testing.F) {
        f.Add(1, 2) // "Seed" corpus
        f.Fuzz(func(t *testing.T, a, b int) {
            Sum(a, b)
            // Проверки на паники или инварианты
        })
    }

Полезные пакеты и сторонние инструменты:

  • net/http/httptest: Пакет из стандартной библиотеки для тестирования HTTP клиентов и серверов.
  • testify/assert и testify/require: Популярная библиотека для более удобных и читаемых утверждений (assertions). assert продолжает выполнение теста после ошибки, require — прерывает.
  • gomock: Фреймворк для генерации моков (mock objects).
  • testcontainers-go: Для интеграционных тестов, требующих внешних зависимостей (например, БД или Kafka), запускаемых в Docker-контейнерах.

Запуск тестов:

# Запустить все тесты в текущем проекте
go test ./...

# Запустить тесты с подробным выводом
go test -v

# Запустить бенчмарки
go test -bench=.

# Рассчитать покрытие тестами и посмотреть отчет
go test -coverprofile=coverage.out
go tool cover -html=coverage.out