Comment puis-je effectuer un traitement de configuration de test global qui ouvre la voie à tous les tests lorsque vous utilisez package de test ?
Par exemple, dans Nunit, il y a un [SetUp]
attribut.
[TestFixture]
public class SuccessTests
{
[SetUp] public void Init()
{ /* Load test data */ }
}
À partir de Go 1.4, vous pouvez implémenter la configuration/démontage (inutile de copier vos fonctions avant/après chaque test). La documentation est décrite ici dans la section principale :
TestMain s’exécute dans le sous-système principal et peut effectuer toutes les opérations de configuration et de démontage nécessaires lors d’un appel à m.Run. Il devrait ensuite appeler os.Exit avec le résultat de m.Run
Il m'a fallu un certain temps pour comprendre que cela signifie que si un test contient une fonction func TestMain(m *testing.M)
, cette fonction sera appelée au lieu d'exécuter le test. Et dans cette fonction, je peux définir le déroulement des tests. Par exemple, je peux implémenter la configuration globale et le démontage:
func TestMain(m *testing.M) { setup() code := m.Run() shutdown() os.Exit(code) }
Quelques autres exemples peuvent être trouvés ici .
La fonctionnalité TestMain ajoutée au framework de test de Go dans la dernière version constitue une solution simple pour plusieurs cas d’utilisation de test. TestMain fournit un raccordement global pour effectuer la configuration et l’arrêt, contrôler l’environnement de test, exécuter un code différent dans un processus enfant ou vérifier les ressources divulguées par le code de test. La plupart des paquets n’auront pas besoin de TestMain, mais c’est un ajout bienvenu pour les moments où cela est nécessaire.
Ceci peut être réalisé en plaçant une fonction init()
dans le fichier _test.go
. Cela sera exécuté avant la fonction init()
.
// package_test.go
package main
func init() {
/* load test data */
}
Le _test.init () sera appelé avant la fonction package init ().
Étant donné une fonction simple à tester un peu:
package math
func Sum(a, b int) int {
return a + b
}
Vous pouvez le tester avec une fonction de configuration qui renvoie la fonction de démontage. Et après avoir appelé setup (), vous pouvez effectuer un appel différé à teardown ().
package math
import "testing"
func setupTestCase(t *testing.T) func(t *testing.T) {
t.Log("setup test case")
return func(t *testing.T) {
t.Log("teardown test case")
}
}
func setupSubTest(t *testing.T) func(t *testing.T) {
t.Log("setup sub test")
return func(t *testing.T) {
t.Log("teardown sub test")
}
}
func TestAddition(t *testing.T) {
cases := []struct {
name string
a int
b int
expected int
}{
{"add", 2, 2, 4},
{"minus", 0, -2, -2},
{"zero", 0, 0, 0},
}
teardownTestCase := setupTestCase(t)
defer teardownTestCase(t)
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
teardownSubTest := setupSubTest(t)
defer teardownSubTest(t)
result := Sum(tc.a, tc.b)
if result != tc.expected {
t.Fatalf("expected sum %v, but got %v", tc.expected, result)
}
})
}
}
L'outil de test va signaler les instructions de journalisation dans la console Shell:
% go test -v
=== RUN TestAddition
=== RUN TestAddition/add
=== RUN TestAddition/minus
=== RUN TestAddition/zero
--- PASS: TestAddition (0.00s)
math_test.go:6: setup test case
--- PASS: TestAddition/add (0.00s)
math_test.go:13: setup sub test
math_test.go:15: teardown sub test
--- PASS: TestAddition/minus (0.00s)
math_test.go:13: setup sub test
math_test.go:15: teardown sub test
--- PASS: TestAddition/zero (0.00s)
math_test.go:13: setup sub test
math_test.go:15: teardown sub test
math_test.go:8: teardown test case
PASS
ok github.com/kare/go-unit-test-setup-teardown 0.010s
%
Vous pouvez transmettre certains paramètres supplémentaires à la configuration/au démontage avec cette approche.
En règle générale, les tests de go ne sont pas écrits dans le même style que les autres langues. Souvent, les fonctions de test sont relativement moins nombreuses, mais chacune contient un ensemble de cas de test pilotés par des tables. Voir cet article écrit par l'un des membres de l'équipe de Go.
Avec un test piloté par une table, vous placez simplement le code de configuration avant la boucle qui exécute les cas de test individuels spécifiés dans la table, puis le code de nettoyage par la suite.
Si vous avez toujours un code de configuration partagé entre des fonctions de test, vous pouvez extraire le code de configuration partagé dans une fonction et utiliser un sync.Once
S'il est important qu'il soit exécuté exactement une fois (ou, comme le suggère une autre réponse, utilisez init()
, mais cela a pour inconvénient que la configuration sera effectuée même si les scénarios de test ne sont pas exécutés (peut-être parce que vous avez limité les scénarios de test en utilisant go test -run <regexp>
.)
Je dirais que si vous pensez que vous avez besoin d'une configuration partagée entre différents tests, celle-ci est exécutée exactement une fois. Vous devez avoir une réflexion si vous en avez vraiment besoin et si un test basé sur une table ne serait pas mieux.
Le framework de test Go n'a rien d'équivalent à attribut SetUp de NUnit (marquant une fonction à appeler avant chaque test de la suite). Il y a quelques options cependant:
Appelez simplement votre fonction SetUp
à partir de chaque test, le cas échéant.
Utilisez une extension du framework de test de Go qui implémente les paradigmes et les concepts xUnit. Trois options fortes me viennent à l’esprit:
Chacune de ces bibliothèques vous encourage à organiser vos tests en suites/fixtures similaires aux autres frameworks xUnit, et appellera les méthodes de configuration sur le type de suite/fixture avant chaque Test*
méthodes.