Comment imprimer dans un test Go à l'aide du package «testing»?

129

J'exécute un test dans Go avec une instruction pour imprimer quelque chose (c'est-à-dire pour le débogage des tests) mais cela n'imprime rien.

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

Lorsque j'exécute go test sur ce fichier, voici la sortie:

ok      command-line-arguments  0.004s

La seule façon de vraiment le faire imprimer, pour autant que je sache, est de l'imprimer via t.Error (), comme ceci:

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

Qui produit ceci:

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

J'ai cherché sur Google et parcouru le manuel, mais je n'ai rien trouvé.

platwp
la source
Cela pourrait être possible pour Go 1.14 (Q1 2010). Voir ma réponse ci-dessous .
VonC
@VonC s / b Q1 2020
user2133814
@ user2133814 D'accord, cela devrait être 2020 en effet, pas 2010. La réponse ci - dessous mentionne 2020. J'ai édité cette réponse, avec une référence à l'article de Dave Cheney sur cette nouvelle fonctionnalité.
VonC

Réponses:

142

Les structures testing.Tet les testing.Bdeux ont une méthode .Loget .Logfqui semble être ce que vous recherchez. .Loget .Logfsont similaires à fmt.Printet fmt.Printfrespectivement.

Voir plus de détails ici: http://golang.org/pkg/testing/#pkg-index

fmt.Ximprimer des relevés font le travail à l' intérieur des tests, mais vous trouverez leur production est probablement pas à l' écran où vous vous attendez à trouver et, par conséquent, pourquoi vous devez utiliser les méthodes d'exploitation forestière dans testing.

Si, comme dans votre cas, vous souhaitez voir les journaux des tests qui n'échouent pas, vous devez fournir go testl' -vindicateur (v pour la verbosité). Plus de détails sur les indicateurs de test peuvent être trouvés ici: https://golang.org/cmd/go/#hdr-Testing_flags

voidlogic
la source
15
t.Log () n'apparaîtra qu'après la fin du test, donc si vous essayez de déboguer un test qui se bloque ou qui fonctionne mal, il semble que vous deviez utiliser fmt. Voir la réponse de PeterSO pour utiliser go test -v pour afficher la sortie de fmt.Println lors de l'exécution de tests.
voutasaurus
142

Par exemple,

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

Commande aller

Description des indicateurs de 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 de paquet

func (* T) Journal

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

Log formate ses arguments en utilisant le formatage par défaut, analogue à Println, et enregistre le texte dans le journal des erreurs. Pour les tests, le texte sera imprimé uniquement si le test échoue ou si l'indicateur -test.v est défini. Pour les benchmarks, le texte est toujours imprimé pour éviter que les performances dépendent de la valeur de l'indicateur -test.v.

peterSO
la source
21
verboseest ce que je cherchais.
cevaris
2
anwa pour afficher la sortie du journal dans la méthode ou vous testez lui
filthy_wizard
7

t.Log()n'apparaîtra pas avant la fin du test, donc si vous essayez de déboguer un test qui se bloque ou qui fonctionne mal, il semble que vous deviez utiliser fmt.

Oui: c'était le cas jusqu'à Go 1.13 (août 2019) inclus.

Et cela a été suivi dans le golang.orgnuméro 24929

Considérez les tests automatisés (idiots) suivants:

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

Si je cours go test -v, je n'obtiens aucune sortie de journal jusqu'à ce que tout TestFoosoit fait , puis aucune sortie jusqu'à ce que tout TestBarsoit terminé, et encore une fois plus de sortie jusqu'à ce que tout TestBazsoit terminé.
C'est bien si les tests fonctionnent, mais s'il y a une sorte de bogue, il y a quelques cas où la mise en mémoire tampon de la sortie du journal est problématique:

  • Lors de l'itération localement, je veux pouvoir faire un changement, exécuter mes tests, voir ce qui se passe dans les journaux immédiatement pour comprendre ce qui se passe, appuyer sur CTRL + C pour arrêter le test tôt si nécessaire, faire un autre changement, re exécutez les tests, et ainsi de suite.
    Si TestFooc'est lent (par exemple, c'est un test d'intégration), je n'obtiens aucune sortie de journal jusqu'à la toute fin du test. Cela ralentit considérablement l'itération.
  • S'il y TestFooa un bogue qui le bloque et ne se termine jamais, je n'obtiendrais aucune sortie de journal. Dans ces cas, t.Loget ne t.Logfsont d'aucune utilité.
    Cela rend le débogage très difficile.
  • De plus, non seulement je n'obtiens aucune sortie de journal, mais si le test se bloque trop longtemps, soit le délai d'expiration du test Go tue le test après 10 minutes, soit si j'augmente ce délai, de nombreux serveurs CI tueront également les tests s'il n'y a pas sortie de journal après un certain temps (par exemple, 10 minutes dans CircleCI).
    Alors maintenant, mes tests sont tués et je n'ai rien dans les journaux pour me dire ce qui s'est passé.

Mais pour (éventuellement) Go 1.14 (Q1 2020): CL 127120

test: sortie du journal de flux en mode détaillé

La sortie est maintenant:

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

Il est en effet dans Go 1.14, comme l'atteste Dave Cheney dans " go test -vstreaming output ":

Dans Go 1.14, go test -vdiffusera la t.Logsortie au fur et à mesure, plutôt que de la thésauriser jusqu'à la fin du test .

Sous Go 1.14, les lignes fmt.Printlnet t.Logsont entrelacées , plutôt que d'attendre la fin du test, ce qui montre que la sortie du test est diffusée lorsqu'elle go test -vest utilisée.

Avantage, selon Dave:

Il s'agit d'une excellente amélioration de la qualité de vie pour les tests de style d'intégration qui sont souvent réessayés pendant de longues périodes lorsque le test échoue.
La t.Logsortie en continu aidera les Gophers à déboguer ces échecs de test sans avoir à attendre que le test complet expire pour recevoir leur sortie.

VonC
la source
5

Pour tester parfois je fais

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

Vous pouvez également imprimer sur:

fmt.Fprintln(os.Stderr, "hello)
Eddy Hernandez
la source
Le premier de ceux-ci peut simplement être fmt.Println("hello").
Duncan Jones
2

t.Loget t.Logfimprimez dans votre test, mais peut souvent être manqué car il s'imprime sur la même ligne que votre test. Ce que je fais, c'est les enregistrer de manière à les faire ressortir, c'est-à-dire

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

qui l'imprime sur le terminal comme,

=== 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
la source
-2

Le *_test.gofichier est une source Go comme les autres, vous pouvez initialiser un nouvel enregistreur à chaque fois si vous avez besoin de vider une structure de données complexe, voici un exemple:

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

Puis, à chaque fois, à chaque 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()
    }*/
}
alessiosavi
la source