Як ви друкуєте в тесті Go, використовуючи пакет "тестування"?


129

Я запускаю тест у Go з заявою щось надрукувати (тобто для налагодження тестів), але він нічого не друкує.

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

Коли я запускаю тест на цей файл, це вихід:

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 (Q1 2010). Дивіться мою відповідь нижче .
VonC

@VonC s / b Q1 2020
користувач2133814

@ 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друк заяву робить роботу в тестах, але ви знайдете їх вихід, ймовірно , не на екрані , де ви очікуєте знайти його і, отже, чому ви повинні використовувати методи каротажу в testing.

Якщо, як у вашому випадку, ви хочете побачити журнали для тестів, які не вдається, ви повинні надати go testв -vпрапор (v для багатослів'я). Детальніше про тестування прапорів можна ознайомитись тут: https://golang.org/cmd/go/#hdr-Testing_flags


15
t.Log () не з’явиться до завершення тесту, тому якщо ви намагаєтеся налагодити тест, який висить або працює погано, здається, вам потрібно використовувати fmt. Дивіться відповідь PeterSO щодо використання 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{})

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


21
verboseце те, що я шукав.
cevaris

2
anwa для перегляду виходу журналу в методе ou тестує себе
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).
    Тож зараз мої тести вбиваються, і я не маю нічого в журналах, щоб сказати, що сталося.

Але для (можливо) переходу 1,14 (Q1 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.