Go: Автоматическое тестирование

Теория: Первый unit-тест и структура тестов

В программировании есть золотое правило: доверяй, но проверяй. Даже если программа работает «на глаз», это не значит, что она работает правильно. Ошибки могут быть незаметными, проявляться только в определённых условиях или после изменений в коде. Чтобы защитить себя и команду, разработчики пишут unit-тесты — небольшие автоматические проверки отдельных функций или модулей.

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

В Go тесты — это такие же .go файлы, только с особым именем. Если файл заканчивается на _test.go, компилятор понимает: внутри находятся тесты. При запуске команды go test язык автоматически находит все такие файлы, компилирует их вместе с кодом и выполняет.

Тестовая функция тоже имеет свои правила. Она должна называться TestИмя, начинаться с большой буквы и принимать аргумент t *testing.T. Через этот объект мы можем сообщать об ошибках, если функция работает не так, как ожидалось. Шаблон выглядит так:

func TestИмяФункции(t *testing.T) {
	// проверки
}

Go сам найдёт такие функции и запустит их при go test.

Первый тест

Допустим, у нас есть простая функция, которая складывает два числа:

// файл calc.go
package calc

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

Теперь создаём рядом файл calc_test.go. Его имя показывает, что внутри тесты:

// файл calc_test.go
package calc

import "testing"

func TestSum(t *testing.T) {
	got := Sum(2, 3) // вызываем нашу функцию
	want := 5        // ожидаем правильный результат

	if got != want { // сравниваем
		// t.Errorf сообщает об ошибке, если ожидания не совпали
		t.Errorf("Sum(2,3) = %d; want %d", got, want)
	}
}

В языке Go каждая тестовая функция принимает аргумент t *testing.T. Этот объект используется для взаимодействия теста с системой тестирования. У него есть разные методы для различных ситуаций.

  • t.Log печатает сообщение в логи.
  • t.Error фиксирует ошибку. Тест продолжает выполняться, но будет считаться проваленным.
  • t.Errorf работает так же, как t.Error, но поддерживает форматирование строк по аналогии с fmt.Printf.
  • t.Fatal фиксирует ошибку и сразу завершает выполнение теста.
  • t.Fatalf делает то же самое, что t.Fatal, но с форматированием.

Таким образом, t.Errorf — это способ сообщить об ошибке в тесте, при этом подставив переменные прямо в текст сообщения.

Пример

package calc

import "testing"

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

func TestSum(t *testing.T) {
	got := Sum(2, 3)
	want := 6 // специально ошибка

	// если результат не совпадает, выводим сообщение об ошибке
	if got != want {
		t.Errorf("Sum(2, 3) = %d; want %d", got, want)
	}
}

При запуске:

--- FAIL: TestSum (0.00s)
    calc_test.go:11: Sum(2, 3) = 5; want 6
FAIL

В отчёте видно: тест не прошёл, полученное значение равно 5, а ожидалось 6.

Если бы вместо этого использовался вызов t.Error("что-то пошло не так"), то в выводе появилась бы только эта фраза без конкретных чисел. Поэтому t.Errorf предпочтительнее: он делает сообщения точными и информативными.

Запускаем тесты

Всё, что нужно, — написать код и тест. Дальше запускаем команду:

go test

Если всё верно, вывод будет таким:

ok  	имя_пакета  	0.002s

Если намеренно поменять ожидание, например want := 6, то тест упадёт и покажет ошибку:

--- FAIL: TestSum (0.00s)
    calc_test.go:10: Sum(2,3) = 5; want 6
FAIL

Так мы видим, что функция не соответствует ожиданиям.

Структура тестов в проекте

Когда тестов становится много, важно держать порядок:

Файл _test.go всегда лежит рядом с кодом. Если у нас есть calc.go, рядом будет calc_test.go. Так легче находить и сопровождать тесты.

Название теста совпадает с функцией, которую проверяем. Тест на функцию SumTestSum. Это сразу ясно при чтении.

Один тест проверяет один сценарий. Если нужно покрыть разные случаи, можно написать несколько функций или использовать табличные тесты (о них позже).

Читаемость важнее всего. Тест — это тоже код. Его должен уметь понять любой разработчик, даже тот, кто пишет в проекте первый день.

Весь процесс сводится к простым шагам: написать функцию, создать рядом файл _test.go, описать Test... и проверить результат через t.Errorf. Даже самые простые проверки позволяют заметить ошибки сразу и не тратить время на ручные проверки. С этого начинается тестирование кода.

Рекомендуемые программы

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845