В разработке программного обеспечения модульное тестирование — это аспект, который нельзя игнорировать. Это не только помогает разработчикам обнаруживать и решать потенциальные проблемы на ранних этапах кодирования, но также обеспечивает надежность, удобство сопровождения и общее качество кода, что очень важно для повышения эффективности разработки и снижения затрат на последующее обслуживание.
Тестовые примеры, которые вы написали ранее, особенно важны, когда вы позже оптимизируете функцию или метод. Если тест пройдет успешно, вы почувствуете облегчение от того, что оптимизированный код не нарушит существующую функциональность; если тест не пройден, это тоже хорошо, потому что вы вовремя обнаружили потенциальную проблему и избежали риска онлайн-сбоя.
существовать Go
на языке,go test
команда и testing
Пакет предоставляет простой и мощный механизм тестирования, позволяющий Gopher
Умение легко писать и выполнять тест-кейсы. В этой статье будет подробно описано, как использовать Go
на языке testing
Обсуждается пакет для написания эффективных модульных тестов go test
Общие параметры команд и их функций, а также повышение качества кода с помощью практических методов подтестов и табличного тестирования. В статье также будет представлено TestMain
Сценарии использования функции, Библиотека инструментов внешнего тестированиянравиться testify
Приложения, а также часто используемые методы утверждения.
Вы готовы? Возьмите чашку любимого кофе или чая и узнайте, прочитав эту статью.
Go
Файлы языковых тестов обычно помещаются в тот же пакет, что и тестируемый исходный файл, а имя файла заканчивается на _test.go
окончание。например,reverse.go
Тестовый файл для файла должен называться reverse_test.go
。так go test
Команда будет правильно распознана и тест выполнен.Test
начинается, за которым следует имя функции, начинающееся с заглавной буквы. Сигнатура тестовой функции: func (t *testing.T)
,в t *testing.T
Параметр, используемый для управления статусом теста и Отчет сбоя теста.├── stringx/
│ ├── reverse.go
│ └── reverse_test.go
существовать reverse.go
внутри:
package stringx
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
существовать reverse_test.go
внутри:
package stringx
import (
"testing"
)
func TestReverse(t *testing.T) {
got := Reverse("Чен Минён")
if got != «Ён Мин Чен» {
t.Errorf("expected Юн Мин Чен, but got %s", got)
}
}
когда Reverse
Если возвращаемый результат неожиданный, используйте t.Errorf
Метод сообщает о неудачном тесте и печатает соответствующую информацию о параметрах.
существовать stringx
Выполнить в каталоге go test
Заказ:
$ go test
PASS
ok test_example/stringx 0.166s
-v
go test -v
$ go test -v
=== RUN TestReverse
--- PASS: TestReverse (0.00s)
PASS
ok test_example/stringx 0.284s
-cover
go test -cover
$ go test -cover
PASS
coverage: 100.0% of statements
ok test_example/stringx 0.174s
-run <regex>
go test -run ^TestFunction$
Просто беги TestFunction
。-bench <regex>
Benchmark
начало).go test -bench .
Запустите все тесты.-benchmem
go test -bench . -benchmem
-coverprofile=<filename>
go test -coverprofile=coverage.out
-covermode=<mode>
set
: Подсчитайте, какие операторы выполняются (по умолчанию).count
: Подсчитайте, сколько раз выполняется каждый оператор.atomic
: Подсчитайте количество выполнений операторов и обеспечьте многопоточную безопасность.go test -covermode=count
-timeout=<duration>
10
минута.go test -timeout=30s
-short
go test -short
-parallel=<n>
Goroutine
количество.go test -parallel=4
-race
go test -race
-count=<n>
go test -count=3
-json
JSON
формат, подходящий для использования с CI
Системная интеграция или анализ журналов.go test -json
-failfast
go test -failfast
Часто используемые комбинации:
go test -coverprofile=coverage.out && go tool cover -html=coverage.out
go test -v ./...
Эти параметры можно гибко комбинировать в соответствии с требованиями тестирования, что помогает улучшить покрытие тестированием, анализ производительности и возможности отладки.
Дополнительные параметры доступны, запустив go help test
команда для просмотра.
лист Тест-драйв(Table-driven tests
)да Go
на языке Общие тестовые шаблоны,Он работает путем организации нескольких тестовых случаев в один (обычно срез).,Используйте цикл для последовательного выполнения каждого тестового примера.,Тем самым улучшая читаемость и ремонтопригодность кода.
package stringx
import (
"testing"
)
func TestReverse(t *testing.T) {
testCases := []struct {
name string
input string
expected string
}{
{"empty string", "", ""}, // Проверка пустой строки
{"reverse Chinese characters", "Чен Минён", «Ён Мин Чен»}, // Проверьте китайские иероглифы
{"reverse English word", "Hello", "olleH"}, // Проверьте английские слова
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got := Reverse(tc.input)
if got != tc.expected {
t.Errorf("expected %s, but got %s", tc.expected, got)
}
})
}
}
Объяснение кода:
testCases
Срез, содержащий несколько структур, каждая структура представляет собой тестовый пример.for _, tc := range testCases
Прокрутите каждый тестовый пример.t.Run(tc.name, ...)
Метод создает субтест для каждого тестового примера.,При выполнении подобных тестов существуют,Имя каждого субтестирезультата можно увидеть в информации, выдаваемой консолью существования.,Удобен для отладки и устранения неполадок.TestMain
В существующем тестовом модуле есть специальная функция, которая используется для выполнения глобальной инициализации и очистки до или после существующего теста. Это точка входа для всего тестового пакета. существовать бежать go test
После команды сначала проверяется, определен ли тестовый файл пакета. TestMain
Функция, если она присутствует, будет вызвана для выполнения теста. если не TestMain
функция, все будут вызываться по умолчанию TextXxx
функция.
TestMain
Сигнатура функции следующая:
TestMain(m *testing.M)
TestMain
Функции обычно сочетаются с setup
и teardown
Функция используется вместе,Первый используется для выполнения некоторой подготовительной работы перед выполнением теста (например, подключения к базе данных).,Конфигурация инициализации и т. д.),Последний используется для выполнения некоторой очистки после выполнения теста (например, закрытия ссылки на базу данных).,удалить временные файлы и т. д.).
Вот пример кода:
package stringx
import (
"fmt"
"os"
"testing"
)
func TestReverse(t *testing.T) {
testCases := []struct {
name string
input string
expected string
}{
{"empty string", "", ""}, // Проверка пустой строки
{"reverse Chinese characters", "Чен Минён", «Ён Мин Чен»}, // Проверьте китайские иероглифы
{"reverse English word", "Hello", "olleH"}, // Проверьте английские слова
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got := Reverse(tc.input)
if got != tc.expected {
t.Errorf("expected %s, but got %s", tc.expected, got)
}
})
}
}
func setup() {
fmt.Println("Before running tests")
}
func teardown() {
fmt.Println("After running tests")
}
func TestMain(m *testing.M) {
setup()
code := m.Run()
teardown()
os.Exit(code)
}
ключ Объяснение кода:
m.Run()
:проходить Этот метод выполняет все тестыфункция.он возвращает целое число,Код состояния, указывающий на тест,Обычно 0
Указывает на успех, а не 0
Указывает на неудавшийся тест.os.Exit(code)
: Вернитесь к результатам теста, чтобы убедиться в правильности статуса выхода.существуют В предыдущем примере кода мы использовали !=
оператор для сравнения результат и ожидаемое значение Они не равны?,Это возможно для базовых типов данных. Однако,когда Нам нужно сравнивать как кусочки、map
При ожидании сложных структур данных используйте их напрямую !=
больше не применимо, и для выполнения сравнения необходимо написать дополнительную логику. Чтобы решить эту проблему, мы можем использовать сторонние библиотеки, такие как testify
,чтобы упростить эти операции сравнения.
testify
дасуществовать Go
Широко используемая сторонняя библиотека тестирования на языке, предоставляющая несколько удобных методов утверждения и поддержку набора тестов. mock
функция, значительно упрощающая написание тестового кода. по сравнению с Go
Входит в комплект testing
Библиотека,testify
Предоставляет более богатые функции для оценки утверждений, особенно когда существование более удобно при работе со сложными структурами данных.
Мы можем установить его с помощью следующей команды testify
Модуль:
go get github.com/stretchr/testify
Далее мы можем преобразовать часть кода, показанного ранее:
if got != tc.expected {
t.Errorf("expected %s, but got %s", tc.expected, got)
}
Переписано как:
assert.Equalf(t, tc.expected, got, "expected %s, but got %s", tc.expected, got)
Если утверждение «когда» не выполнено, будет напечатана следующая информация.
testify/assert
Предоставляет множество функций утверждения, упрощающих выполнение сложных операций сравнения. Ниже приведены некоторые часто используемые функции утверждения:
assert.Equal
Утверждайте, что два значения равны, применимо к базовым типам, структурам и т. д.assert.Equal(t, «Ён Мин Чен», Reverse("Чен Минён")) // Reverse("Чен Минён" Равно ли это «Ён Мин Чен»
assert.NotNil
Утверждать, что объект не nil
。var obj = &struct{}{}
assert.NotNil(t, obj)
assert.True
Условие утверждения true
。var b bool
assert.True(t, b)
assert.False
Условие утверждения false
。var b bool
assert.False(t, b)
assert.ElementsMatch
Используется для сравнения того, содержат ли два среза одни и те же элементы, независимо от порядка элементов.expected := []int{1, 2, 3, 4}
actual := []int{4, 3, 2, 1}
assert.ElementsMatch(t, expected, actual)
assert.Len
набор утверждений(как нарезанный、map
и т. д.) равно указанному значению.assert.Len(t, []int{1, 2, 3}, 3)
Дополнительную информацию о функциях см. testify/assert。
Кроме assert
Сумка,testify
В библиотеке также есть еще один require
пакет, это связано с assert
Функции пакетов аналогичны и используются для утверждений. Основное различие между ними заключается в том, как бороться с неудачными тестами:
assert
Пакет зарегистрирует сбой, но тест продолжит выполнение последующего кода.assert.Equal(t, "Чен Минён", Reverse("Чен Минён")) // Регистрируйте сбой при сбое, но продолжайте выполнение кода, стоящего за ним.
assert.Equal(t, «Ён Мин Чен», Reverse("Чен Минён")) // Это утверждение все равно будет выполнено
require
Пакет немедленно прекратит выполнение предварительного теста и выдаст сообщение об ошибке. Тест не продолжает выполнять последующий код.require.Equal(t, "Чен Минён", Reverse("Чен Минён")) // Немедленно прекратить выполнение последующего кода в случае сбоя.
require.Equal(t, «Ён Мин Чен», Reverse("Чен Минён")) // Если предыдущее утверждение не выполнено, это не будет выполнено.
Мы можем выбрать подходящий пакет в соответствии с конкретным сценарием тестирования, например, когда некоторые ключевые шаги должны гарантировать, что тест будет завершен, если он не пройден. require
,И за не такключ Можно использовать шаги assert
,Чтобы тест мог продолжать выполняться и получать больше результатов.
Я считаю, что благодаря этой статье вы научились существовать. Go
Язык для эффективного написания Модульное тестирование。от Базовая структура тест к листу тестирования драйверов с использованием внешних библиотек testify
для более гибких операций утверждения и для go test
Владение командами и их часто используемыми параметрами.
Модульное тестирование — не только ключевое звено в улучшении качества кода,Это также важная практика для обеспечения долгосрочной стабильности проекта. Будь то личный проект или большая командная разработка,Каждый должен обратить внимание на важность тестирования на протяжении всего процесса разработки.
Здравствуйте, я Чэнь Мингён, разработчик, который любит технологии и готов ими делиться, а также энтузиаст открытого исходного кода.
Путь к успеху не переполнен. Вы заинтересованы в поиске партнера?
Следуйте за мной, добавляйте меня в друзья, учитесь и совершенствуйтесь вместе!