моя контактная информация
Почтамезофия@protonmail.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
В языке Go модульное тестирование реализуется через пакет тестирования в стандартной библиотеке, который предоставляет набор функций, которые делают написание, запуск и управление модульными тестами простыми и эффективными.
Правила именования тестовых файлов
Правило именования тестовых файлов в Go заключается в добавлении_test.go
.Например, если у вас естьcalculator.go
файл, соответствующий тестовый файл должен бытьcalculator_test.go
。
Правила именования тестовых функций
Тестовая функция должна начинаться сTest
начинается, и за ним может следовать любая непустая строка, напримерTestAdd
、TestSubtract
ждать.
использовать testing.T
Делайте утверждения и сообщайте об ошибках
В тестовой функции используйтеtesting.T
Введите параметры для управления состоянием теста и выходными данными.вы можете использоватьt.Error*
、t.Fail*
и другие методы для указания на неудачу теста и вывода соответствующей информации об ошибках.
Функция калькулятора определена в пакете калькулятора, и ее конкретная реализация выглядит следующим образом:
package calculator
func Add(a, b int) int {
return a + b
}
В текущем каталоге мы создаем тестовый файл 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)
}
}
Чтобы запустить этот модульный тест, используйте команду go test.В командной строке введите каталог, содержащий Calculator.go и Calculator_test.go, а затем выполнитеgo test
, эти результаты заключаются в следующем
go test
PASS
ok modu 0.226s
Добавьте следующую тестовую функцию в калькулятор_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)
}
}
Чтобы лучше видеть выполнение каждого тестового примера в выходных результатах, мы можем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
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
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)
}
}
при выполнении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
С помощью тестовых групп и подтестов вы можете добавлять больше тестовых случаев и просматривать результаты в более удобной форме.
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)
}
})
}
}
бегать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
Язык 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)
}
})
}
}
использоватьgo test -cover
чтобы просмотреть тестовое покрытие
go test -cover
PASS
modu coverage: 100.0% of statements
ok modu 1.149s
При проведении модульного тестирования на языке 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)
}
})
}
Доступен сейчас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)
})
}
testify/require
иметьtestify/assert
Все функции утверждения, единственная разница между ними заключается вtestify/require
Если обнаружен неудачный тестовый пример, тест будет немедленно прекращен.