Обмен технологиями

Перейти к модульному тестированию

2024-07-12

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

В языке Go модульное тестирование реализуется через пакет тестирования в стандартной библиотеке, который предоставляет набор функций, которые делают написание, запуск и управление модульными тестами простыми и эффективными.

1. Правила

  • Правила именования тестовых файлов
    Правило именования тестовых файлов в Go заключается в добавлении_test.go .Например, если у вас естьcalculator.go файл, соответствующий тестовый файл должен бытьcalculator_test.go

  • Правила именования тестовых функций
    Тестовая функция должна начинаться сTest начинается, и за ним может следовать любая непустая строка, напримерTestAddTestSubtract ждать.

  • использовать testing.T Делайте утверждения и сообщайте об ошибках
    В тестовой функции используйтеtesting.T Введите параметры для управления состоянием теста и выходными данными.вы можете использоватьt.Error*t.Fail* и другие методы для указания на неудачу теста и вывода соответствующей информации об ошибках.

2. Пример модульного теста

2.1 Одиночный тестовый пример

Функция калькулятора определена в пакете калькулятора, и ее конкретная реализация выглядит следующим образом:

package calculator

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

В текущем каталоге мы создаем тестовый файл Calculator_test.go и определяем тестовую функцию следующим образом:

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

Чтобы запустить этот модульный тест, используйте команду go test.В командной строке введите каталог, содержащий Calculator.go и Calculator_test.go, а затем выполнитеgo test, эти результаты заключаются в следующем

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

2.2 Несколько тестовых примеров

Добавьте следующую тестовую функцию в калькулятор_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

Чтобы лучше видеть выполнение каждого тестового примера в выходных результатах, мы можемgo test -vпараметры, позволяющие ему выводить полные результаты испытаний.

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 Укажите выполняемые тестовые примеры

go test -run Команда может запускать тесты в соответствии с указанным режимом. Эта команда поддерживает регулярные выражения для выбора тестовых функций для запуска.

Например, после исправления варианта использования TestAdd2 передайтеgo tes -run=Add2Запустите только тестовый пример TestAdd2, результат будет

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

4. Пропустите некоторые тестовые случаи
Добавить новую функцию тестирования

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

при выполненииgo test -shorКогда t, оно будет пропущеноtesting.Short()Отмеченный тестовый пример, результат

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. Тестовые группы и субтесты

3.1 Тестовые группы и субтесты

С помощью тестовых групп и подтестов вы можете добавлять больше тестовых случаев и просматривать результаты в более удобной форме.

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

бегатьgo test -v,оказаться

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 Параллельное тестирование

Язык Go по своей сути поддерживает параллелизм, поэтому, добавивt.Parallel()Добиться распараллеливания тестов драйверов.

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 Тестовое покрытие

использоватьgo test -coverчтобы просмотреть тестовое покрытие

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

4. Инструментарий для модульного тестирования Go — свидетельствуйте

При проведении модульного тестирования на языке Go, поскольку официальная функция утверждения не встроена, нам обычно приходится использовать большое количествоif...else... заявление о проверке результатов теста.Однако, используя сторонние библиотеки, такие какtestify/assert, мы можем легко вызвать множество часто используемых функций утверждения, которые не только упрощают тестовый код, но также генерируют четкую и понятную информацию с описанием ошибки, которая помогает нам быстро обнаружить проблему.

В приведенном выше примере мы используемif...else...Заявление о проверке результатов теста

	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

Доступен сейчасtestify/assertВышеупомянутый процесс принятия решения упрощается следующим образом:

	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/requireиметьtestify/assertВсе функции утверждения, единственная разница между ними заключается вtestify/requireЕсли обнаружен неудачный тестовый пример, тест будет немедленно прекращен.