Как устроено тестирование в Go?

Ответ

Тестирование в Go является первоклассной возможностью языка и встроено в стандартный инструментарий. Для этого используется пакет testing и команда go test.

Основные принципы:

  • Тесты находятся в файлах с суффиксом _test.go в том же пакете, что и тестируемый код.
  • Команда go test автоматически находит и запускает такие файлы.

Основные виды тестов:

  1. Юнит-тесты (Unit Tests)

    • Функция должна начинаться с Test, например, TestMyFunction.
    • Принимает один аргумент: t *testing.T.
    • С помощью t можно сообщать об ошибках (t.Error, t.Errorf), прерывать тест (t.Fatal, t.Fatalf) или организовывать под-тесты (t.Run).
      
      // main.go
      func Add(a, b int) int {
      return a + b
      }

    // main_test.go func TestAdd(t *testing.T) { // Популярный подход "table-driven tests" testCases := []struct{ a, b, expected int }{ {1, 2, 3}, {0, 0, 0}, {-1, 1, 0}, }

    for _, tc := range testCases {
        t.Run("test case", func(t *testing.T) {
            if result := Add(tc.a, tc.b); result != tc.expected {
                t.Errorf("Add(%d, %d) = %d; want %d", tc.a, tc.b, result, tc.expected)
            }
        })
    }

    }

  2. Бенчмарки (Benchmark Tests)

    • Функция начинается с Benchmark, например, BenchmarkMyFunction.
    • Принимает b *testing.B.
    • Код, производительность которого измеряется, помещается в цикл for i := 0; i < b.N; i++.
    • Запускаются командой go test -bench=..
  3. Тесты-примеры (Example Tests)

    • Функция начинается с Example, например, ExampleMyFunction.
    • Используются для документации: их код отображается в godoc. Они также являются исполняемыми тестами: Go проверяет, что вывод в stdout соответствует комментарию // Output:.
  4. Фаззинг-тесты (Fuzzing)

    • Добавлены в Go 1.18. Предназначены для поиска неожиданных багов путем подачи в функцию случайных входных данных.
    • Функция начинается с Fuzz, например, FuzzMyFunction.
    • Принимает f *testing.F.

Полезные команды и флаги:

  • go test: запустить все тесты в текущем пакете.
  • go test ./...: запустить тесты во всех под-пакетах.
  • go test -v: показать детальный вывод, включая имена тестов.
  • go test -cover: показать процент покрытия кода тестами.
  • go test -run TestName: запустить конкретный тест по имени (регулярное выражение).
  • t.Parallel(): позволяет запускать тесты (или под-тесты) параллельно, что ускоряет выполнение.