Partage de technologie

Passez aux tests unitaires

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Dans le langage Go, les tests unitaires sont implémentés via le package de test de la bibliothèque standard, qui fournit un ensemble de fonctions rendant l'écriture, l'exécution et la gestion des tests unitaires simples et efficaces.

1. Règles

  • Tester les règles de dénomination des fichiers
    La règle de dénomination des fichiers de test dans Go consiste à ajouter_test.go .Par exemple, si vous avez uncalculator.go fichier, le fichier de test correspondant doit êtrecalculator_test.go

  • Règles de dénomination des fonctions de test
    La fonction de test doit commencer parTest commence et peut être suivi de n'importe quelle chaîne non vide, par exempleTestAddTestSubtract attendez.

  • utiliser testing.T Faire des assertions et signaler des erreurs
    Dans la fonction test, utiliseztesting.T Saisissez des paramètres pour gérer l’état et la sortie des tests.vous pouvez utilisert.Error*t.Fail* et d'autres méthodes pour indiquer l'échec du test et produire des informations d'erreur pertinentes.

2. Exemple de test unitaire

2.1 Cas de test unique

Une fonction de calculatrice est définie dans le package de calculatrice, et l'implémentation spécifique est la suivante :

package calculator

func Add(a, b int) int {
	return a + b
}
  • 1
  • 2
  • 3
  • 4
  • 5

Dans le répertoire courant, nous créons un fichier de test calculator_test.go et définissons une fonction de test comme suit :

package calculator

import "testing"


func TestAdd(t *testing.T) {
	result := Add(1, 2)
	expected := 3
	if result != expected {
		t.Errorf("Add(1,2) return %d, expected %d", result, expected)
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Pour exécuter ce test unitaire, utilisez la commande go test.Dans la ligne de commande, entrez le répertoire contenant calculator.go et calculator_test.go, puis exécutezgo test, ces résultats sont les suivants

go test
PASS
ok      modu    0.226s
  • 1
  • 2
  • 3

2.2 Plusieurs cas de test

Ajoutez la fonction de test suivante dans calculator_test.go :

func TestAdd2(t *testing.T) {
	result := Add(3, 2)
	expected := 3
	if result != expected {
		t.Errorf("Add(1,2) return %d, expected %d", result, expected)
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Afin de mieux voir l'exécution de chaque scénario de test dans les résultats de sortie, nous pouvonsgo test -vparamètres pour lui permettre de produire des résultats de test complets.

go test -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestAdd2
    calculator_test.go:17: Add(1,2) return 5, expected 3
--- FAIL: TestAdd2 (0.00s)
FAIL
exit status 1
FAIL    modu    0.216s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2.3 Spécifier les cas de test en cours d'exécution

go test -run La commande peut exécuter des tests selon le mode spécifié. Cette commande prend en charge les expressions régulières pour sélectionner les fonctions de test à exécuter.

Par exemple, après avoir corrigé le cas d'utilisation TestAdd2, transmettezgo tes -run=Add2Exécutez uniquement le scénario de test TestAdd2, le résultat est

go test -run=Add2 -v
=== RUN   TestAdd2
--- PASS: TestAdd2 (0.00s)
PASS
ok      modu    0.198s
  • 1
  • 2
  • 3
  • 4
  • 5

4. Ignorer certains cas de test
Ajouter une nouvelle fonction de test

func TestAdd3(t *testing.T) {
	if testing.Short() {
        t.Skip("short模式下会跳过该测试用例")
    }
	
	result := Add(3, 2)
	expected := 5
	if result != expected {
		t.Errorf("Add(1,2) return %d, expected %d", result, expected)
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

lors de l'exécutiongo test -shorQuand t, il sera ignorétesting.Short()Le cas de test marqué, le résultat est

go test -short -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestAdd2
--- PASS: TestAdd2 (0.00s)
=== RUN   TestAdd3
    calculator_test.go:23: short模式下会跳过该测试用例
--- SKIP: TestAdd3 (0.00s)
PASS
ok      modu    0.635s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3. Groupes de tests et sous-tests

3.1 Groupes de tests et sous-tests

Grâce aux groupes de tests et aux sous-tests, vous pouvez ajouter davantage de cas de test et visualiser les résultats de manière plus conviviale.

func TestAdd(t *testing.T) {
	tests := []struct {
		name     string
		x, y     int
		expected int
	}{
		{"Add1", 1, 2, 3},
		{"Add2", 3, 3, 6},
		{"Add3", 4, 5, 8},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := Add(tc.x, tc.y)
			if result != tc.expected {
				t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
			}
		})
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

courirgo test -v,s'avérer

go test -v
=== RUN   TestAdd
=== RUN   TestAdd/Add2
=== RUN   TestAdd/Add3
    calculator_test.go:51: Add(4, 5) returned 9, expected 8
--- FAIL: TestAdd (0.00s)
    --- PASS: TestAdd/Add1 (0.00s)
    --- PASS: TestAdd/Add2 (0.00s)
    --- FAIL: TestAdd/Add3 (0.00s)
FAIL
exit status 1
FAIL    modu    0.190s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3.2 Tests parallèles

Le langage Go prend intrinsèquement en charge la concurrence, donc en ajoutantt.Parallel()Réaliser la parallélisation des tests de pilotes.

func TestAdd(t *testing.T) {
	t.Parallel()  // 将 TLog 标记为能够与其他测试并行运行
	// 这里使用匿名结构体定义了若干个测试用例
	// 并且为每个测试用例设置了一个名称
	tests := []struct {
		name     string
		x, y     int
		expected int
	}{
		{"Add1", 1, 2, 3},
		{"Add2", 3, 3, 6},
		{"Add3", 4, 5, 8},
	}

	for _, tc := range tests {
		tc := tc  // 注意这里重新声明tt变量(避免多个goroutine中使用了相同的变量)
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()  // 将每个测试用例标记为能够彼此并行运行
			result := Add(tc.x, tc.y)
			if result != tc.expected {
				t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
			}
		})
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

3.3 Couverture des tests

utilisergo test -coverpour voir la couverture des tests

go test -cover
PASS
        modu    coverage: 100.0% of statements
ok      modu    1.149s
  • 1
  • 2
  • 3
  • 4

4. Accédez à la boîte à outils de tests unitaires – témoignez

Lors de la réalisation de tests unitaires en langage Go, étant donné que la fonction d'assertion officielle n'est pas intégrée, nous devons généralement utiliser un grand nombre deif...else... déclaration pour vérifier les résultats des tests.Cependant, en utilisant des bibliothèques tierces telles quetestify/assert, nous pouvons facilement appeler une variété de fonctions d'assertion couramment utilisées, qui non seulement simplifient le code de test, mais génèrent également des informations de description d'erreur claires et faciles à comprendre pour nous aider à localiser rapidement le problème.

Dans l'exemple ci-dessus, nous utilisonsif...else...Déclaration pour vérifier les résultats des tests

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := Add(tc.x, tc.y)
			if result != tc.expected {
				t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
			}
		})
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Disponible dès maintenanttestify/assertLe processus de jugement ci-dessus est simplifié comme suit :

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := Add(tc.x, tc.y)
			assert.Equal(t, result, tc.expected)
		})
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

testify/requireavoirtestify/assertToutes les fonctions d'assertion, la seule différence entre elles esttestify/requireSi un scénario de test ayant échoué est rencontré, le test sera immédiatement terminé.