Создание тестов в GO

Создание и запуск тестов в GO + Emacs

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

  1. Именование файлов:

    • Тестовые файлы должны заканчиваться на _test.go.
    • Пример: main.gomain_test.go.
  2. Именование функций:

    • Тестовые функции должны начинаться с Test (для юнит-тестов) или Benchmark (для бенчмарков).
    • Пример:
      func TestAdd(t *testing.T) { ... }
      func BenchmarkAdd(b *testing.B) { ... }
      
  3. Параметры тестовых функций:

    • Юнит-тесты принимают *testing.T.
    • Бенчмарки принимают *testing.B.
    • Примеры тестов (t.Error, t.Fail, t.Run для подтестов).
  4. Табличные тесты (Table-Driven Tests):

    • Рекомендуемый подход для покрытия разных сценариев.
    • Пример:
      func TestAdd(t *testing.T) {
          cases := []struct {
              a, b, expected int
          }{
              {1, 2, 3},
              {0, 0, 0},
              {-1, 1, 0},
          }
          for _, tc := range cases {
              result := Add(tc.a, tc.b)
              if result != tc.expected {
                  t.Errorf("Add(%d, %d) = %d; want %d", tc.a, tc.b, result, tc.expected)
              }
          }
      }
      
  5. Покрытие кода (Coverage):

    • Замер покрытия:
      go test -cover
      go test -coverprofile=coverage.out && go tool cover -html=coverage.out
      
  6. Моки и тестовые данные:

    • Используйте интерфейсы для замены зависимостей (например, sqlmock для тестирования SQL-запросов).

Автоматизация тестов в Emacs для Go

  1. go-mode:

    • Основной режим для работы с Go в Emacs.
    • Установка:
      (use-package go-mode
        :ensure t)
      
  2. go-test.el:

    • Пакет для запуска тестов (встроен в go-mode).
    • Команды:
      • M-x go-test-current-test — запуск текущего теста.
      • M-x go-test-current-file — тестирование текущего файла.
      • M-x go-test-current-project — тесты всего проекта.
      • M-x go-test-current-benchmark — запуск бенчмарка.
  3. flycheck / golangci-lint:

    • Проверка кода и тестов в реальном времени.
  4. dap-mode (Debug Adapter Protocol):

    • Отладка тестов (аналог VS Code).

Требования к тестовым файлам

  1. Расположение:

    • Тестовые файлы должны быть в том же пакете (package mathpackage math_test для black-box тестирования).
  2. Доступ к символам:

    • Если тестируемые функции/переменные должны быть экспортированы (UpperCase).
  3. Использование testing:

    • Обязателен импорт "testing".
  4. Тестовые данные:

    • Можно использовать testdata/ для дополнительных файлов (например, JSON-фикстур).

Основные команды для тестов

  1. Запуск всех тестов:

    go test ./...
    
  2. Запуск конкретного теста:

    go test -run TestAdd
    
  3. Покрытие кода:

    go test -coverprofile=cover.out && go tool cover -html=cover.out
    
  4. Бенчмарки:

    go test -bench .
    
  5. Пропуск кеширования:

    go test -count=1
    
  6. Вербозный вывод:

    go test -v
    
  7. Параллельные тесты:

    func TestParallel(t *testing.T) {
        t.Parallel()
        // ...
    }
    

Бенчмарки (Benchmarks) в Go

Бенчмарки в Go — это тесты производительности, которые измеряют скорость выполнения кода (время на операцию, аллокации памяти и т. д.). Они помогают находить узкие места в программе и сравнивать разные реализации алгоритмов.


Как работают бенчмарки?

  1. Именование функции:

    • Должно начинаться с Benchmark.
    • Принимает *testing.B (аналог *testing.T в обычных тестах).
    • Пример:
      func BenchmarkSum(b *testing.B) {
          for i := 0; i < b.N; i++ {
              Sum(1, 2) // Тестируемая функция
          }
      }
      
  2. Цикл b.N:

    • Go автоматически подбирает N (количество итераций), чтобы получить стабильные результаты.
    • Чем быстрее функция, тем больше итераций будет сделано.
  3. Запуск бенчмарка:

    go test -bench .
    
    • Флаг -bench принимает регулярное выражение для выбора бенчмарков (. — все).
    • Пример вывода:
      $$BenchmarkSum-8 1000000000 0.265 ns/op$$
      • BenchmarkSum-8 — название теста (-8 — количество CPU).
      • 1000000000 — количество итераций (b.N).
      • 0.265 ns/op — время на одну операцию (наносекунды).

Полезные флаги для бенчмарков

Флаг Описание Пример
-benchmem Показывать аллокации памяти go test -bench . -benchmem
-benchtime Установить время выполнения go test -bench . -benchtime=5s
-count Количество прогонов go test -bench . -count=3
-cpu Тестировать на разном числе CPU go test -bench . -cpu=1,2,4

Пример бенчмарка

Допустим, есть функция сложения:

// sum.go
package math

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

Тест и бенчмарк:

// sum_test.go
package math

import "testing"

func TestSum(t *testing.T) {
    if Sum(1, 2) != 3 {
        t.Error("Ожидается 3")
    }
}

func BenchmarkSum(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Sum(1, 2)
    }
}

Запуск:

go test -bench . -benchmem

Вывод:

$$BenchmarkSum-8 1000000000 0.265 ns/op 0 B/op 0 allocs/op$$
  • 0.265 ns/op — 0.265 наносекунд на операцию.
  • 0 B/op — 0 байт выделено за итерацию.
  • 0 allocs/op — 0 аллокаций памяти.

Сравнение производительности

Бенчмарки полезны для сравнения разных реализаций. Например:

func BenchmarkSlow(b *testing.B) {
    for i := 0; i < b.N; i++ {
        SlowFunction()
    }
}

func BenchmarkFast(b *testing.B) {
    for i := 0; i < b.N; i++ {
        FastFunction()
    }
}

Запуск:

go test -bench . -benchmem

Покажет, какая функция работает быстрее и использует меньше памяти.


Бенчмарки в Go — это тесты производительности.

  • Запускаются через go test -bench.
  • Показывают время на операцию (ns/op), аллокации памяти (B/op, allocs/op).

Если нужно углублённо анализировать производительность, можно использовать pprof:

go test -bench . -cpuprofile=cpu.out
go tool pprof cpu.out