Come si stampa in un test Go utilizzando il pacchetto "testing"?


129

Sto eseguendo un test in Go con un'istruzione per stampare qualcosa (cioè per il debug dei test) ma non stampa nulla.

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

Quando eseguo go test su questo file, questo è l'output:

ok      command-line-arguments  0.004s

L'unico modo per farlo stampare davvero, per quanto ne so, è stamparlo tramite t.Error (), in questo modo:

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

Che produce questo:

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

Ho cercato su Google e ho esaminato il manuale ma non ho trovato nulla.


Questo potrebbe essere possibile per Go 1.14 (Q1 2010). Vedi la mia risposta di seguito .
VonC

@VonC s / b Q1 2020
user2133814

@ user2133814 D'accordo, dovrebbe essere davvero il 2020, non il 2010. La risposta sotto menziona il 2020. Ho modificato la risposta, con un riferimento all'articolo di Dave Cheney su quella nuova funzionalità.
VonC

Risposte:


142

Gli struct testing.Ted testing.Bentrambi hanno un metodo .Loge .Logfche sembra essere quello che stai cercando. .Loge .Logfsono simili a fmt.Printe fmt.Printfrispettivamente.

Vedi maggiori dettagli qui: http://golang.org/pkg/testing/#pkg-index

fmt.Xstampare dichiarazioni fanno lavoro all'interno test, ma si trovano la loro uscita non è probabilmente sulla schermata in cui ci si aspetta di trovare e, quindi, il motivo per cui si dovrebbe usare i metodi di registrazione in testing.

Se, come nel tuo caso, vuoi vedere i log per i test che non falliscono, devi fornire go testil -vflag (v per verbosity). Maggiori dettagli sui flag di test possono essere trovati qui: https://golang.org/cmd/go/#hdr-Testing_flags


15
t.Log () non verrà visualizzato fino al completamento del test, quindi se stai cercando di eseguire il debug di un test che è in sospeso o che funziona male, sembra che tu debba usare fmt. Vedere la risposta di PeterSO per l'utilizzo di go test -v per mostrare l'output di fmt.Println durante l'esecuzione dei test.
voutasaurus

142

Per esempio,

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

Comanda vai

Descrizione dei flag di test

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

Test del pacchetto

func (* T) Log

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

Log formatta i suoi argomenti usando la formattazione predefinita, analoga a Println, e registra il testo nel log degli errori. Per i test, il testo verrà stampato solo se il test fallisce o se è impostato il flag -test.v. Per i benchmark, il testo viene sempre stampato per evitare che le prestazioni dipendano dal valore del flag -test.v.


21
verboseè quello che stavo cercando.
cevaris

2
anwa per visualizzare l'output del log nel moethod ou stai testando se stesso
filthy_wizard

7

t.Log()non verrà visualizzato fino al completamento del test, quindi se stai tentando di eseguire il debug di un test in sospeso o che funziona male, sembra che tu debba usare fmt.

Sì: questo era il caso fino al Go 1.13 (agosto 2019) incluso.

E questo fu seguito nel golang.orgnumero 24929

Considera i seguenti (stupidi) test automatizzati:

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)
    }
}

Se eseguo go test -v, non ottengo alcun output di log fino a quando non TestFooè stato completato tutto , quindi nessun output fino a quando non TestBarè stato completato e di nuovo non viene più visualizzato alcun output finché non TestBazè stato completato tutto.
Questo va bene se i test funzionano, ma se c'è una sorta di bug, ci sono alcuni casi in cui il buffering dell'output del log è problematico:

  • Durante l'iterazione locale, voglio essere in grado di apportare una modifica, eseguire i miei test, vedere cosa sta succedendo immediatamente nei log per capire cosa sta succedendo, premere CTRL + C per chiudere il test in anticipo se necessario, apportare un'altra modifica, ri- eseguire i test e così via.
    Se TestFooè lento (ad esempio, è un test di integrazione), non ottengo alcun output di log fino alla fine del test. Ciò rallenta notevolmente l'iterazione.
  • Se TestFooha un bug che lo blocca e non viene mai completato, non otterrei alcun output di log. In questi casi t.Loge t.Logfnon servono affatto.
    Questo rende il debug molto difficile.
  • Inoltre, non solo non ottengo alcun output di log, ma se il test si blocca troppo a lungo, il timeout del test Go interrompe il test dopo 10 minuti, o se aumento tale timeout, molti server CI interromperanno anche i test se non c'è log output dopo un certo periodo di tempo (ad esempio, 10 minuti in CircleCI).
    Quindi ora i miei test vengono interrotti e non ho nulla nei registri che mi dica cosa è successo.

Ma per (forse) Go 1.14 (Q1 2020): CL 127120

testing: output del log del flusso in modalità dettagliata

L'output ora è:

=== 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

È infatti in Go 1.14, come Dave Cheney attesta in " go test -vstreaming output ":

In Go 1.14, go test -vtrasmetterà l' t.Logoutput come accade, invece di accumularlo fino alla fine del test .

In Go 1.14 le righe fmt.Printlne t.Logsono interleaved , invece di attendere il completamento del test, dimostrando che l'output del test viene trasmesso in streaming quando go test -vviene utilizzato.

Vantaggio, secondo Dave:

Si tratta di un grande miglioramento della qualità della vita per i test di stile di integrazione che spesso riprovano per lunghi periodi quando il test fallisce.
L' t.Logoutput in streaming aiuterà i Gopher a eseguire il debug di tali errori di test senza dover attendere il timeout dell'intero test per ricevere l'output.


5

Per i test a volte lo faccio

fmt.Fprintln(os.Stdout, "hello")

Inoltre, puoi stampare su:

fmt.Fprintln(os.Stderr, "hello)

Il primo di questi può essere solo fmt.Println("hello").
Duncan Jones

2

t.Loge t.Logfstampi nel tuo test, ma spesso può essere perso poiché stampa sulla stessa riga del test. Quello che faccio è registrarli in un modo che li faccia risaltare, ad es

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)
})

che lo stampa sul terminale come,

=== 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

Il *_test.gofile è una sorgente Go come le altre, puoi inizializzare un nuovo logger ogni volta se devi scaricare una struttura dati complessa, ecco un esempio:

// 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
}

Quindi, ogni volta, in ogni test:

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()
    }*/
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.