Как вывести текст в консоль при тестировании в Go (пакет testing)?
Использование t.Log и t.Logf для вывода в тестах
Вы совершенно правы: fmt.Println в Go-тестах работает не так, как в обычных программах. По умолчанию стандартный вывод (stdout) подавляется, чтобы не засорять результаты тестирования. Вместо этого нужно использовать методы объекта *testing.T.
Основные методы для вывода:
t.Log(args...)— выводит сообщение, аналогичноfmt.Println.t.Logf(format string, args...)— выводит форматированное сообщение, аналогичноfmt.Printf.
Вот как это работает на вашем примере:
package main
import (
"testing"
)
func Sum(a, b int) int {
return a + b
}
func TestSum(t *testing.T) {
result := Sum(2, 3)
t.Logf("Результат сложения: %d", result) // Вывод: Результат сложения: 5
}
Теперь, если вы запустите go test, вывод НЕ появится. Почему? Потому что по умолчанию go test показывает только результаты проваленных тестов или итоговую статистику. Чтобы увидеть вывод t.Log, нужно использовать флаг -v (verbose):
go test -v
Вывод будет выглядеть примерно так:
=== RUN TestSum
main_test.go:12: Результат сложения: 5
--- PASS: TestSum (0.00s)
PASS
ok example.com/project 0.002s
Когда использовать t.Log, а когда fmt.Println?
t.Log/t.Logf— для отладки и логирования в тестах. Вывод привязан к конкретному тесту и появляется только с флагом-v. Это правильный и рекомендуемый способ.fmt.Println— технически тоже работает, но его вывод появляется в любом случае (даже без-v), смешивается с результатами тестов и может сбивать с толку. Используйте его только если вам нужно гарантированно вывести что-то вне контекста тестирования (например, вTestMain).
Важные нюансы
- Вывод при провале теста: Если тест падает (вызывается
t.Fatal,t.Errorfи т.д.), все сообщенияt.Logиз этого теста автоматически выводятся даже без флага-v. Это помогает понять, почему тест провалился. - Параллельные тесты: При запуске тестов с
t.Parallel()выводt.Logможет перемешиваться. Для синхронизации используйтеt.Runи подтесты. - Не злоупотребляйте: В идеале тесты должны быть самодостаточными и не требовать ручного просмотра логов. Используйте
t.Logтолько для отладки, а в финальной версии теста удалите лишние логи или замените их на ассерты (t.Errorf).
Пример с подтестами и разными уровнями логирования
func TestSumMultipleCases(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"positive", 2, 3, 5},
{"negative", -1, -2, -3},
{"zero", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Sum(tt.a, tt.b)
t.Logf("Тест %s: %d + %d = %d", tt.name, tt.a, tt.b, got)
if got != tt.want {
t.Errorf("Sum(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want)
}
})
}
}
Запустите go test -v и увидите аккуратный вывод для каждого подтеста.
Использование t.Error и t.Fatal как альтернатива логированию
Иногда вместо того, чтобы просто выводить значения для отладки, бывает полезнее сразу сообщить об ошибке, если результат не соответствует ожидаемому. Это делает тесты более надёжными и самодокументируемыми.
Методы t.Error и t.Errorf помечают тест как проваленный, но продолжают его выполнение. Методы t.Fatal и t.Fatalf немедленно останавливают тест. При этом сообщения, переданные в эти методы, выводятся в консоль даже без флага -v.
Пример:
func TestSum(t *testing.T) {
result := Sum(2, 3)
expected := 5
if result != expected {
t.Errorf("Ожидалось %d, получено %d", expected, result)
}
}
Если тест провалится, вы увидите:
--- FAIL: TestSum (0.00s)
main_test.go:12: Ожидалось 5, получено 6
FAIL
Этот подход предпочтительнее, чем t.Log, потому что:
- Вывод появляется только при ошибке, не засоряя консоль при успешном прохождении.
- Тест становится автоматически проверяемым — не нужно вручную смотреть логи.
- Сообщение об ошибке содержит контекст, который помогает быстро понять причину провала.
Используйте t.Log для временной отладки, но в финальной версии теста заменяйте его на ассерты с понятными сообщениями об ошибках.
Ответов пока нет.
Войдите чтобы оставить ответ