Avatar ·

Как вывести текст в консоль при тестировании в Go (пакет testing)?

Всем привет! Я только начал изучать Go и пишу unit-тесты с использованием стандартного пакета `testing`. У меня есть простая функция, которую я хочу протестировать, и для отладки мне нужно вывести какие-то промежуточные значения в консоль, чтобы убедиться, что тест работает правильно. Вот пример моего кода: ```go package main import "testing" func Sum(a, b int) int { return a + b } func TestSum(t *testing.T) { result := Sum(2, 3) // Как мне вывести result в консоль? } ``` Я пробовал использовать `fmt.Println(result)` внутри функции `TestSum`, но при запуске теста командой `go test` я не вижу никакого вывода. Может быть, я что-то делаю не так? Нужно ли мне использовать какой-то специальный метод из пакета `testing`? Подскажите, пожалуйста, как правильно выводить отладочную информацию во время выполнения тестов в Go. Заранее спасибо! <<>>

Использование 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 для временной отладки, но в финальной версии теста заменяйте его на ассерты с понятными сообщениями об ошибках.