Как вы печатаете в тесте Go с помощью пакета «testing»?


129

Я запускаю тест в Go с оператором, чтобы что-то напечатать (например, для отладки тестов), но он ничего не печатает.

func TestPrintSomething(t *testing.T) {
    fmt.Println("Say hi")
}

Когда я запускаю go test для этого файла, это результат:

ok      command-line-arguments  0.004s

Насколько я знаю, единственный способ действительно заставить его распечатать - это распечатать его через t.Error (), например:

func TestPrintSomethingAgain(t *testing.T) {
    t.Error("Say hi")
}

Что выводит это:

Say hi
--- FAIL: TestPrintSomethingAgain (0.00 seconds)
    foo_test.go:35: Say hi
FAIL
FAIL    command-line-arguments  0.003s
gom:  exit status 1

Я погуглил и просмотрел руководство, но ничего не нашел.


Это может быть возможно в Go 1.14 (первый квартал 2010 г.). Смотрите мой ответ ниже .
VonC

@VonC s / b Q1 2020
user2133814

@ user2133814 Согласен, это действительно должен быть 2020 год, а не 2010. В приведенном ниже ответе упоминается 2020 год. Я отредактировал указанный ответ со ссылкой на статью Дейва Чейни об этой новой функции.
VonC

Ответы:


142

В Структуры testing.Tи testing.Bоба имеют .Logи .Logfметод, звук будет то , что вы ищете. .Logи .Logfаналогичны fmt.Printи fmt.Printfсоответственно.

Подробнее см. Здесь: http://golang.org/pkg/testing/#pkg-index

fmt.XОператоры print действительно работают внутри тестов, но вы обнаружите, что их вывод, вероятно, не находится на экране, где вы ожидаете его найти, и, следовательно, почему вам следует использовать методы регистрации в testing.

Если, как в вашем случае, вы хотите увидеть журналы для тестов, которые не удается, вы должны предоставить go testв -vфлаг (v для многословия). Более подробную информацию о флагах тестирования можно найти здесь: https://golang.org/cmd/go/#hdr-Testing_flags


15
t.Log () не появится до тех пор, пока тест не будет завершен, поэтому, если вы пытаетесь отладить тест, который зависает или работает плохо, вам кажется, что вам нужно использовать fmt. См. Ответ ПетерСО об использовании go test -v, чтобы показать вывод fmt.Println при запуске тестов.
voutasaurus

142

Например,

package verbose

import (
    "fmt"
    "testing"
)

func TestPrintSomething(t *testing.T) {
    fmt.Println("Say hi")
    t.Log("Say bye")
}

go test -v
=== RUN TestPrintSomething
Say hi
--- PASS: TestPrintSomething (0.00 seconds)
    v_test.go:10: Say bye
PASS
ok      so/v    0.002s

Команда идти

Описание флагов тестирования

-v
Verbose output: log all tests as they are run. Also print all
text from Log and Logf calls even if the test succeeds.

Тестирование пакетов

func (* T) Журнал

func (c *T) Log(args ...interface{})

Log форматирует свои аргументы, используя форматирование по умолчанию, аналогично Println, и записывает текст в журнал ошибок. Для тестов текст будет напечатан только в том случае, если тест не пройден или установлен флаг -test.v. Для тестов текст всегда печатается, чтобы производительность не зависела от значения флага -test.v.


21
verboseэто то, что я искал.
cevaris

2
anwa для просмотра вывода журнала в методе, который вы тестируете сами
filthy_wizard

7

t.Log()не будет отображаться до тех пор, пока тест не будет завершен, поэтому, если вы пытаетесь отладить тест, который зависает или работает плохо, вам кажется, что вам нужно использовать fmt.

Да: так было до версии Go 1.13 (август 2019 г.) включительно.

За этим последовал golang.orgвыпуск 24929.

Рассмотрим следующие (глупые) автоматизированные тесты:

func TestFoo(t *testing.T) {
    t.Parallel()

  for i := 0; i < 15; i++ {
        t.Logf("%d", i)
        time.Sleep(3 * time.Second)
    }
}

func TestBar(t *testing.T) {
    t.Parallel()

  for i := 0; i < 15; i++ {
        t.Logf("%d", i)
        time.Sleep(2 * time.Second)
    }
}

func TestBaz(t *testing.T) {
    t.Parallel()

  for i := 0; i < 15; i++ {
        t.Logf("%d", i)
        time.Sleep(1 * time.Second)
    }
}

Если я запускаю go test -v, я не получаю вывода журнала, пока все не TestFooбудет выполнено , затем не будет вывода, пока все не TestBarбудет выполнено, и снова не будет вывода, пока все не TestBazбудет выполнено.
Это нормально, если тесты работают, но если есть какая-то ошибка, есть несколько случаев, когда буферизация вывода журнала проблематична:

  • При локальной итерации я хочу иметь возможность вносить изменения, запускать свои тесты, сразу же видеть, что происходит в журналах, чтобы понять, что происходит, нажимать CTRL + C, чтобы закрыть тест раньше, если необходимо, вносить другое изменение, повторно запустить тесты и так далее.
    Если TestFooвыполняется медленно (например, это интеграционный тест), я не получаю вывода журнала до самого конца теста. Это значительно замедляет итерацию.
  • Если TestFooесть ошибка, из-за которой он зависает и никогда не завершается, я бы вообще не получил вывода журнала. В этих случаях они t.Logи t.Logfвовсе не нужны.
    Это очень затрудняет отладку.
  • Более того, я не только не получаю вывода журнала, но и если тест зависает слишком долго, либо тайм-аут теста Go завершает тест через 10 минут, либо если я увеличиваю этот тайм-аут, многие серверы CI также завершают тесты, если нет вывод журнала через определенное время (например, 10 минут в CircleCI).
    Итак, теперь мои тесты убиты, и у меня нет ничего в журналах, чтобы рассказать мне, что произошло.

Но для (возможно) Go 1.14 ( первый квартал 2020 г.): CL 127120

тестирование: потоковый вывод журнала в подробном режиме

Теперь вывод:

=== RUN   TestFoo
=== PAUSE TestFoo
=== RUN   TestBar
=== PAUSE TestBar
=== RUN   TestGaz
=== PAUSE TestGaz
=== CONT  TestFoo
    TestFoo: main_test.go:14: hello from foo
=== CONT  TestGaz
=== CONT  TestBar
    TestGaz: main_test.go:38: hello from gaz
    TestBar: main_test.go:26: hello from bar
    TestFoo: main_test.go:14: hello from foo
    TestBar: main_test.go:26: hello from bar
    TestGaz: main_test.go:38: hello from gaz
    TestFoo: main_test.go:14: hello from foo
    TestGaz: main_test.go:38: hello from gaz
    TestBar: main_test.go:26: hello from bar
    TestFoo: main_test.go:14: hello from foo
    TestGaz: main_test.go:38: hello from gaz
    TestBar: main_test.go:26: hello from bar
    TestGaz: main_test.go:38: hello from gaz
    TestFoo: main_test.go:14: hello from foo
    TestBar: main_test.go:26: hello from bar
--- PASS: TestFoo (1.00s)
--- PASS: TestGaz (1.00s)
--- PASS: TestBar (1.00s)
PASS
ok      dummy/streaming-test    1.022s

Это действительно в Go 1.14, как утверждает Дэйв Чейни в « go test -vпотоковом выводе »:

В Go 1.14 выводится go test -vпотоком по мере его поступления, а не накапливается до конца тестового прогона .t.Log

Под Go 1.14 fmt.Printlnи t.Logлинии перемежаются , а не ждать окончания тестирования, демонстрации того, что тестовый выход в потоковом режиме, когда go test -vиспользуется.

Преимущество, по словам Дэйва:

Это большое улучшение качества жизни для тестов стиля интеграции, которые часто повторяются в течение длительного времени, когда тест не работает.
Потоковый t.Logвывод поможет Gophers отлаживать эти сбои теста, не дожидаясь, пока истечет время всего теста, чтобы получить их результат.



2

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

t.Run("FindIntercomUserAndReturnID should find an intercom user", func(t *testing.T) {

    id, err := ic.FindIntercomUserAndReturnID("test3@test.com")
    assert.Nil(t, err)
    assert.NotNil(t, id)

    t.Logf("\n\nid: %v\n\n", *id)
})

который выводит его на терминал как,

=== RUN   TestIntercom
=== RUN   TestIntercom/FindIntercomUserAndReturnID_should_find_an_intercom_user
    TestIntercom/FindIntercomUserAndReturnID_should_find_an_intercom_user: intercom_test.go:34:

        id: 5ea8caed05a4862c0d712008

--- PASS: TestIntercom (1.45s)
    --- PASS: TestIntercom/FindIntercomUserAndReturnID_should_find_an_intercom_user (1.45s)
PASS
ok      github.com/RuNpiXelruN/third-party-delete-service   1.470s

-2

*_test.goФайл является источник Go , как и другие, вы можете инициализировать новую запись регистратора каждый раз , если вам нужно сбросить сложную структуру данных, здесь пример:

// initZapLog is delegated to initialize a new 'log manager'
func initZapLog() *zap.Logger {
    config := zap.NewDevelopmentConfig()
    config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
    config.EncoderConfig.TimeKey = "timestamp"
    config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
    logger, _ := config.Build()
    return logger
}

Затем каждый раз, в каждом тесте:

func TestCreateDB(t *testing.T) {
    loggerMgr := initZapLog()
    // Make logger avaible everywhere
    zap.ReplaceGlobals(loggerMgr)
    defer loggerMgr.Sync() // flushes buffer, if any
    logger := loggerMgr.Sugar()
    logger.Debug("START")
    conf := initConf()
    /* Your test here
    if false {
        t.Fail()
    }*/
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.