Go: Автоматическое тестирование
Теория: Первый unit-тест и структура тестов
В программировании есть золотое правило: доверяй, но проверяй. Даже если программа работает «на глаз», это не значит, что она работает правильно. Ошибки могут быть незаметными, проявляться только в определённых условиях или после изменений в коде. Чтобы защитить себя и команду, разработчики пишут unit-тесты — небольшие автоматические проверки отдельных функций или модулей.
Как устроены тесты в Go
В Go тесты — это такие же .go файлы, только с особым именем. Если файл заканчивается на _test.go, компилятор понимает: внутри находятся тесты. При запуске команды go test язык автоматически находит все такие файлы, компилирует их вместе с кодом и выполняет.
Тестовая функция тоже имеет свои правила. Она должна называться TestИмя, начинаться с большой буквы и принимать аргумент t *testing.T. Через этот объект мы можем сообщать об ошибках, если функция работает не так, как ожидалось. Шаблон выглядит так:
Go сам найдёт такие функции и запустит их при go test.
Первый тест
Допустим, у нас есть простая функция, которая складывает два числа:
Теперь создаём рядом файл calc_test.go. Его имя показывает, что внутри тесты:
В языке Go каждая тестовая функция принимает аргумент t *testing.T. Этот объект используется для взаимодействия теста с системой тестирования. У него есть разные методы для различных ситуаций.
t.Logпечатает сообщение в логи.t.Errorфиксирует ошибку. Тест продолжает выполняться, но будет считаться проваленным.t.Errorfработает так же, какt.Error, но поддерживает форматирование строк по аналогии сfmt.Printf.t.Fatalфиксирует ошибку и сразу завершает выполнение теста.t.Fatalfделает то же самое, чтоt.Fatal, но с форматированием.
Таким образом, t.Errorf — это способ сообщить об ошибке в тесте, при этом подставив переменные прямо в текст сообщения.
Пример
При запуске:
В отчёте видно: тест не прошёл, полученное значение равно 5, а ожидалось 6.
Если бы вместо этого использовался вызов t.Error("что-то пошло не так"), то в выводе появилась бы только эта фраза без конкретных чисел. Поэтому t.Errorf предпочтительнее: он делает сообщения точными и информативными.
Запускаем тесты
Всё, что нужно, — написать код и тест. Дальше запускаем команду:
Если всё верно, вывод будет таким:
Если намеренно поменять ожидание, например want := 6, то тест упадёт и покажет ошибку:
Так мы видим, что функция не соответствует ожиданиям.
Структура тестов в проекте
Когда тестов становится много, важно держать порядок:
Файл _test.go всегда лежит рядом с кодом. Если у нас есть calc.go, рядом будет calc_test.go. Так легче находить и сопровождать тесты.
Название теста совпадает с функцией, которую проверяем. Тест на функцию Sum — TestSum. Это сразу ясно при чтении.
Один тест проверяет один сценарий. Если нужно покрыть разные случаи, можно написать несколько функций или использовать табличные тесты (о них позже).
Читаемость важнее всего. Тест — это тоже код. Его должен уметь понять любой разработчик, даже тот, кто пишет в проекте первый день.
Весь процесс сводится к простым шагам: написать функцию, создать рядом файл _test.go, описать Test... и проверить результат через t.Errorf. Даже самые простые проверки позволяют заметить ошибки сразу и не тратить время на ручные проверки. С этого начинается тестирование кода.



