W jaki sposób drukujesz w teście Go przy użyciu pakietu „testing”?

129

Uruchamiam test w Go z instrukcją, aby coś wydrukować (np. Do debugowania testów), ale to nic nie drukuje.

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

Kiedy uruchamiam test go na tym pliku, jest to wynik:

ok      command-line-arguments  0.004s

Jedynym sposobem, aby naprawdę wydrukować to, o ile wiem, jest wydrukowanie go za pomocą t.Error (), na przykład:

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

Który daje to:

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

Wyszukałem w Google i przejrzałem instrukcję, ale nic nie znalazłem.

platwp
źródło
To może być możliwe dla Go 1.14 (Q1 2010). Zobacz moją odpowiedź poniżej .
VonC
@VonC s / b Q1 2020
user2133814
@ user2133814 Zgoda, rzeczywiście powinien być rok 2020, a nie rok 2010. Poniższa odpowiedź wspomina rok 2020. Redagowałem tę odpowiedź, odnosząc się do artykułu Dave'a Cheney'a na temat tej nowej funkcji.
VonC

Odpowiedzi:

142

Struktury testing.Ti testing.Boba mają metodę .Logi .Logfmetodę, które brzmią, aby być tym, czego szukasz. .Logi .Logfsą podobne do fmt.Printi fmt.Printfodpowiednio.

Zobacz więcej szczegółów tutaj: http://golang.org/pkg/testing/#pkg-index

fmt.Xwydrukować sprawozdanie zrobić pracę wewnątrz testów, ale znajdziesz ich produkcja nie jest chyba na ekranie, gdzie można oczekiwać, aby go znaleźć, a co za tym idzie, dla których warto korzystać z metod rejestrowania się testing.

Jeśli, jak w twoim przypadku, chcesz zobaczyć logi do badań, które nie są upadających, trzeba dostarczyć go testdo -vflag (v) do gadatliwości. Więcej szczegółów na temat flag testowych można znaleźć tutaj: https://golang.org/cmd/go/#hdr-Testing_flags

voidlogic
źródło
15
t.Log () pojawi się dopiero po zakończeniu testu, więc jeśli próbujesz zdebugować test, który się zawiesza lub działa źle, wydaje się, że musisz użyć fmt. Zobacz odpowiedź PeterSO na użycie go test -v do pokazania wyniku fmt.Println podczas wykonywania testów.
voutasaurus
142

Na przykład,

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

Polecenie idź

Opis flag testowych

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

Testowanie pakietów

func (* T) Log

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

Dziennik formatuje argumenty przy użyciu domyślnego formatowania, analogicznego do Println, i zapisuje tekst w dzienniku błędów. W przypadku testów tekst zostanie wydrukowany tylko wtedy, gdy test zakończy się niepowodzeniem lub ustawiono opcję -test.v. W przypadku testów tekst jest zawsze drukowany, aby uniknąć zależności wydajności od wartości flagi -test.v.

peterSO
źródło
21
verbosejest tym, czego szukałem.
cevaris
2
anwa, aby wyświetlić dane wyjściowe dziennika w metodzie ou testujesz siebie
filthy_wizard
7

t.Log()pojawi się dopiero po zakończeniu testu, więc jeśli próbujesz zdebugować test, który się zawiesza lub działa źle, wydaje się, że musisz go użyć fmt.

Tak: tak było do wersji Go 1.13 (sierpień 2019) włącznie.

I tak było w golang.orgnumerze 24929

Rozważ następujące (głupie) testy automatyczne:

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

Jeśli uruchomię go test -v, nie otrzymuję danych wyjściowych, dopóki wszystko nie TestFoozostanie wykonane , a następnie żadnych danych wyjściowych, dopóki wszystko nie TestBarzostanie wykonane, i znowu żadnych danych wyjściowych, dopóki wszystko nie TestBazzostanie wykonane.
Jest to w porządku, jeśli testy działają, ale jeśli jest jakiś błąd, jest kilka przypadków, w których buforowanie danych wyjściowych dziennika jest problematyczne:

  • Podczas iteracji lokalnej chcę mieć możliwość wprowadzenia zmiany, uruchomienia testów, natychmiastowego sprawdzenia, co się dzieje w dziennikach, aby zrozumieć, co się dzieje, nacisnąć CTRL + C, aby w razie potrzeby zakończyć test wcześniej, wprowadzić kolejną zmianę, ponownie uruchomić testy i tak dalej.
    Jeśli TestFoojest powolny (np. Jest to test integracji), żadne dane wyjściowe dziennika nie są wyświetlane aż do samego końca testu. To znacznie spowalnia iterację.
  • Jeśli TestFooma błąd, który powoduje, że się zawiesza i nigdy się nie kończy, nie otrzymywałbym żadnego wyjścia dziennika. W tych przypadkach, t.Logi t.Logfnie mają zastosowania w ogóle.
    To sprawia, że ​​debugowanie jest bardzo trudne.
  • Co więcej, nie tylko nie otrzymuję danych wyjściowych dziennika, ale jeśli test zawiesza się zbyt długo, limit czasu testu Go zabija test po 10 minutach lub jeśli zwiększę ten limit czasu, wiele serwerów CI również wyłącza testy, jeśli nie ma logować dane wyjściowe po określonym czasie (np. 10 minut w CircleCI).
    Więc teraz moje testy są zakończone i nie mam nic w dziennikach, aby powiedzieć mi, co się stało.

Ale dla (prawdopodobnie) Go 1.14 (Q1 2020): CL 127120

testowanie: przesyłanie danych wyjściowych dziennika w trybie szczegółowym

Wynik to teraz:

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

Rzeczywiście tak jest w Go 1.14, jak potwierdza Dave Cheney w „ go test -vtransmisji strumieniowej ”:

W Go 1.14, go test -vbędzie przesyłać strumieniowo t.Logdane wyjściowe tak, jak to się dzieje, zamiast gromadzić je do końca przebiegu testowego .

W Go 1.14 linie fmt.Printlni t.Logprzeplatane , zamiast czekać na zakończenie testu, co pokazuje, że wyjście testu jest przesyłane strumieniowo, gdy go test -vjest używane.

Zaleta, według Dave'a:

Jest to duża poprawa jakości życia w przypadku testów w stylu integracji, które często są ponawiane przez długie okresy, gdy test kończy się niepowodzeniem.
Strumieniowe przesyłanie t.Logdanych pomoże Świstakom debugować te niepowodzenia testów bez konieczności czekania, aż upłynie cały czas testu, aby otrzymać wynik.

VonC
źródło
5

Czasami do testów

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

Możesz także drukować na:

fmt.Fprintln(os.Stderr, "hello)
Eddy Hernandez
źródło
Pierwszym z nich może być po prostu fmt.Println("hello").
Duncan Jones
2

t.Logi t.Logfwydrukuj w swoim teście, ale często można go przeoczyć, ponieważ drukuje w tym samym wierszu co test. Loguję je w sposób, który je wyróżnia, tj

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

    id, err := ic.FindIntercomUserAndReturnID("[email protected]")
    assert.Nil(t, err)
    assert.NotNil(t, id)

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

który drukuje go na terminalu jako,

=== 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
RuNpiXelruN
źródło
-2

*_test.goPlik jest źródłem Go jak inni, można zainicjować nową rejestratora za każdym razem, gdy trzeba zrzucić złożoną strukturę danych, tutaj przykład:

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

Następnie za każdym razem w każdym teście:

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()
    }*/
}
alessiosavi
źródło