Как вывести текст в консоль при тестировании в Go (пакет testing)?
Почему fmt.Println не работает в тестах Go?
Вы столкнулись с особенностью работы Go-тестов. По умолчанию go test выводит только итоговый результат (PASS/FAIL) и сообщения об ошибках. Вывод через fmt.Println подавляется, чтобы не засорять консоль при прогоне сотен тестов. Это сделано намеренно — тесты должны быть чистыми и предсказуемыми.
Однако есть несколько способов увидеть отладочную информацию. Рассмотрим их от простого к продвинутому.
Способ 1: Флаг -v (verbose)
Самый простой способ — запустить тесты с флагом -v (verbose, подробный режим). Тогда весь вывод, включая fmt.Println, будет показан:
go test -v
Теперь ваш код заработает:
func TestSum(t *testing.T) {
result := Sum(2, 3)
fmt.Println("Result is:", result) // Будет видно с флагом -v
if result != 5 {
t.Errorf("Expected 5, got %d", result)
}
}
Вывод станет таким:
=== RUN TestSum
Result is: 5
--- PASS: TestSum (0.00s)
PASS
Недостаток: нужно всегда помнить про флаг -v. Если забудете — вывод пропадёт.
Способ 2: Метод t.Log() и t.Logf() (рекомендуемый)
Пакет testing предоставляет специальные методы для логирования: t.Log() и t.Logf(). Их главное преимущество — они работают как fmt.Print/fmt.Printf, но:
- Вывод показывается только при запуске с флагом
-v - Вывод показывается автоматически, если тест упал (даже без
-v) - Логи привязываются к конкретному тесту, что удобно при параллельном запуске
Пример:
func TestSum(t *testing.T) {
result := Sum(2, 3)
t.Logf("Result is: %d", result) // Логирование, привязанное к тесту
if result != 5 {
t.Errorf("Expected 5, got %d", result)
}
}
Если тест упадёт, вы увидите:
=== RUN TestSum
main_test.go:10: Result is: 4
--- FAIL: TestSum (0.00s)
main_test.go:12: Expected 5, got 4
FAIL
Обратите внимание: лог появился, хотя мы не использовали -v. Это очень удобно для отладки упавших тестов.
Способ 3: Принудительный вывод через t.Error() или t.Fatal()
Если вам нужно гарантированно показать информацию, даже без -v, можно использовать методы, которые помечают тест как упавший:
t.Error(args...)— логирует ошибку и продолжает выполнение тестаt.Fatal(args...)— логирует ошибку и немедленно останавливает тест
Пример:
func TestSum(t *testing.T) {
result := Sum(2, 3)
t.Log("Проверяем результат...")
if result != 5 {
t.Errorf("Ожидали 5, получили %d", result) // Покажет это сообщение всегда
}
// Если хотите просто показать значение без ошибки — не используйте Error/Fatal
}
Важно: Не злоупотребляйте этим! Используйте t.Error только для настоящих ошибок, иначе тест будет считаться упавшим.
Способ 4: os.Stdout и кастомный логгер (для продвинутых)
Если вам нужно перенаправить вывод в отдельный файл или обработать его, можно использовать стандартный пакет log или напрямую писать в os.Stdout. Но это уже излишество для обычных тестов.
Резюме
- Используйте
t.Log()/t.Logf()для отладочного вывода — это идиоматичный способ в Go - Запускайте тесты с
go test -v, чтобы видеть все логи - Не используйте
fmt.Println— он не привязан к тесту и путает вывод - Для сообщений об ошибках используйте
t.Error/t.Fatal
Теперь вы сможете эффективно отлаживать свои тесты!
<<Альтернативный подход: Использование testing.T.Cleanup() для логирования после теста
Иногда нужно вывести сводную информацию после завершения теста, независимо от того, упал он или прошёл. Для этого можно использовать метод t.Cleanup(), который регистрирует функцию, выполняющуюся после завершения теста:
func TestSum(t *testing.T) {
result := Sum(2, 3)
t.Cleanup(func() {
t.Logf("Очистка после теста. Результат был: %d", result)
})
if result != 5 {
t.Errorf("Expected 5, got %d", result)
}
}
Этот метод полезен, когда вы хотите гарантированно вывести финальное состояние или освободить ресурсы (закрыть файлы, соединения). Логи из Cleanup также подчиняются правилам: показываются с -v или при падении теста.
Дополнительный совет: Если вы пишете табличные тесты (table-driven tests), используйте t.Run() для подтестов. Каждый подтест может иметь свои логи:
func TestSumTable(t *testing.T) {
tests := []struct{
a, b, expected int
}{
{2, 3, 5},
{0, 0, 0},
{-1, 1, 0},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("%d+%d", tt.a, tt.b), func(t *testing.T) {
result := Sum(tt.a, tt.b)
t.Logf("Result: %d", result)
if result != tt.expected {
t.Errorf("got %d, want %d", result, tt.expected)
}
})
}
}
Такой подход делает вывод максимально структурированным: каждый подтест выводится отдельно, и логи не смешиваются.
Ответов пока нет.
Войдите чтобы оставить ответ