Wie drucken Sie in einem Go-Test mit dem Testpaket?


129

Ich führe in Go einen Test mit einer Anweisung aus, um etwas zu drucken (dh zum Debuggen von Tests), aber es wird nichts gedruckt.

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

Wenn ich go test für diese Datei ausführe, ist dies die Ausgabe:

ok      command-line-arguments  0.004s

Die einzige Möglichkeit, es wirklich zum Drucken zu bringen, besteht meines Wissens darin, es über t.Error () zu drucken, wie folgt:

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

Welches gibt dies aus:

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

Ich habe gegoogelt und das Handbuch durchgesehen, aber nichts gefunden.


Dies könnte für Go 1.14 (Q1 2010) möglich sein. Siehe meine Antwort unten .
VonC

@VonC s / b Q1 2020
user2133814

@ user2133814 Einverstanden, es sollte tatsächlich 2020 sein, nicht 2010. In der folgenden Antwort wird 2020 erwähnt. Ich habe diese Antwort unter Bezugnahme auf Dave Cheneys Artikel zu dieser neuen Funktion bearbeitet.
VonC

Antworten:


142

Die Strukturen testing.Tund testing.Bbeide haben eine .Logund .Logf-Methode, die genau das klingt, wonach Sie suchen. .Logund .Logfsind ähnlich fmt.Printund fmt.Printfsind.

Weitere Details finden Sie hier: http://golang.org/pkg/testing/#pkg-index

fmt.Xprint - Anweisungen tun innen Tests Arbeit, aber Sie werden ihre Ausgabe ist wahrscheinlich nicht auf dem Bildschirm , wo Sie erwarten , dass es zu finden und damit , warum Sie die Logging - Methoden in verwenden sollten testing.

Wenn Sie wie in Ihrem Fall die Protokolle für Tests anzeigen möchten, die nicht fehlschlagen, müssen Sie go testdas -vFlag (v für Ausführlichkeit) angeben. Weitere Details zum Testen von Flags finden Sie hier: https://golang.org/cmd/go/#hdr-Testing_flags


15
t.Log () wird erst nach Abschluss des Tests angezeigt. Wenn Sie also versuchen, einen Test zu debuggen, der hängt oder schlecht funktioniert, müssen Sie anscheinend fmt verwenden. Siehe PeterSOs Antwort für die Verwendung von go test -v, um die Ausgabe von fmt.Println beim Ausführen von Tests anzuzeigen.
Voutasaurus

142

Beispielsweise,

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

Befehl gehen

Beschreibung der Testflags

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

Pakettests

func (* T) Log

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

Das Protokoll formatiert seine Argumente analog zur Druckformatierung analog zu Println und zeichnet den Text im Fehlerprotokoll auf. Bei Tests wird der Text nur gedruckt, wenn der Test fehlschlägt oder das Flag -test.v gesetzt ist. Bei Benchmarks wird der Text immer gedruckt, um zu vermeiden, dass die Leistung vom Wert des Flags -test.v abhängt.


21
verboseist das, wonach ich gesucht habe.
Cevaris

2
anwa, um die Protokollausgabe in der Methode anzuzeigen, die Sie selbst testen
filthy_wizard

7

t.Log()wird erst nach Abschluss des Tests angezeigt. Wenn Sie also versuchen, einen Test zu debuggen, der hängt oder schlecht funktioniert, müssen Sie ihn verwenden fmt.

Ja, das war bis Go 1.13 (August 2019) der Fall.

Und das folgte in golang.orgAusgabe 24929

Betrachten Sie die folgenden (dummen) automatisierten Tests:

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

Wenn ich laufe go test -v, erhalte ich keine Protokollausgabe, bis alles TestFooerledigt ist , dann keine Ausgabe, bis alles TestBarerledigt ist, und wieder keine Ausgabe mehr, bis alles TestBazerledigt ist.
Dies ist in Ordnung, wenn die Tests funktionieren, aber wenn es einen Fehler gibt, gibt es einige Fälle, in denen das Puffern der Protokollausgabe problematisch ist:

  • Wenn ich lokal iteriere, möchte ich in der Lage sein, eine Änderung vorzunehmen, meine Tests auszuführen, zu sehen, was in den Protokollen sofort passiert, um zu verstehen, was vor sich geht, STRG + C zu drücken, um den Test bei Bedarf vorzeitig zu beenden, eine weitere Änderung vorzunehmen und erneut zu ändern Führen Sie die Tests aus und so weiter.
    Wenn TestFooes langsam ist (z. B. ein Integrationstest), erhalte ich bis zum Ende des Tests keine Protokollausgabe. Dies verlangsamt die Iteration erheblich.
  • Wenn TestFooes einen Fehler gibt, der dazu führt, dass er hängen bleibt und nie abgeschlossen wird, erhalte ich überhaupt keine Protokollausgabe. In diesen Fällen t.Logund t.Logfsind überhaupt nicht von Nutzen.
    Dies macht das Debuggen sehr schwierig.
  • Darüber hinaus erhalte ich nicht nur keine Protokollausgabe, sondern wenn der Test zu lange hängt, beendet entweder das Go-Test-Timeout den Test nach 10 Minuten, oder wenn ich dieses Timeout erhöhe, beenden viele CI-Server auch Tests, wenn keine vorhanden sind Protokollausgabe nach einer bestimmten Zeit (z. B. 10 Minuten in CircleCI).
    Jetzt sind meine Tests beendet und ich habe nichts in den Protokollen, was mir passiert wäre.

Aber für (möglicherweise) Go 1.14 (Q1 2020): CL 127120

Testen: Stream-Protokollausgabe im ausführlichen Modus

Die Ausgabe ist jetzt:

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

Es ist in der Tat in Go 1.14, wie Dave Cheney in " go test -vStreaming Output " bestätigt:

In Go 1.14 go test -vwird die t.LogAusgabe sofort gestreamt, anstatt sie bis zum Ende des Testlaufs zu horten .

Unter Go 1.14 werden die Zeilen fmt.Printlnund verschachtelt , anstatt auf den Abschluss des Tests zu warten. Dies zeigt, dass die Testausgabe bei Verwendung gestreamt wird.t.Loggo test -v

Vorteil laut Dave:

Dies ist eine hervorragende Verbesserung der Lebensqualität für Tests im Integrationsstil, die häufig über einen längeren Zeitraum wiederholt werden, wenn der Test fehlschlägt.
Durch das Streamen der t.LogAusgabe können Gophers diese Testfehler beheben, ohne warten zu müssen, bis der gesamte Test abgelaufen ist, um die Ausgabe zu erhalten.


5

Zum Testen mache ich manchmal

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

Sie können auch drucken auf:

fmt.Fprintln(os.Stderr, "hello)

Die erste davon kann einfach sein fmt.Println("hello").
Duncan Jones

2

t.Logund t.Logfdrucken Sie in Ihrem Test aus, können aber oft übersehen werden, da er in derselben Zeile wie Ihr Test gedruckt wird. Was ich tue, ist, sie auf eine Weise zu protokollieren, die sie hervorhebt, dh

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

das druckt es auf dem Terminal als,

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

Die *_test.goDatei ist wie die anderen eine Go-Quelle. Sie können jedes Mal einen neuen Logger initialisieren, wenn Sie eine komplexe Datenstruktur sichern müssen. Hier ein Beispiel:

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

Dann jedes Mal in jedem 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()
    }*/
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.