В предыдущей статье мы рассказали, как пройти go test Внедрить модульное тестирование: Разработка через тестирование против. golang Модульное тестирование
но Модульное тестированиетолько go test В этой статье представлено самое основное использование. go test Более продвинутые тесты и тесты безопасности параллелизма.
Часто нам нужно не только проверить правильность выполнения программы, но мы часто уделяем больше внимания потреблению производительности при выполнении программы. Ведь прежде чем проект выйдет в сеть, сколько ресурсов необходимо для его развертывания и как. большой трафик, который проект может выдержать, не понимайте этого. Если у вас недостаточно денег, вы не сможете гарантировать безопасность своего онлайн-бизнеса, и последствия будут катастрофическими. Инструмент go test также обеспечивает поддержку стресс-тестирования и других функций — эталонного тестирования.
go test Тест предоставляет целевой сегмент кода, который выполняет N Статистика времени выполнения рассчитывается для реализации функции стресс-тестирования. и Модульное похожие, Покапроект xxx_test.go Напишите в файле следующий метод для записи функции тестирования:
func BenchmarkXxx(*testing.B) {
// Тело тестовой функции
}
Например:
func BenchmarkFib10(b *testing.B) {
for n := 0; n < b.N; n++ {
Fib(10)
}
}
осуществлять:
go test -bench=.
покажет:
$ go test -bench=. BenchmarkFib10-4 3000000 424 ns/op PASS ok chapter09/testing 1.724s
Указывает, что он был выполнен 3 000 000 раз, что заняло 1,724 секунды, а каждый вызов занял 424 наносекунды.
Мы также можем указать время выполнения теста через -benchtime:
$ go test -bench=Fib40 -benchtime=20s BenchmarkFib40-4 30 838675800 ns/op
type B struct {
common
importPath string // import path of the package containing the benchmark
context *benchContext
N int
previousN int // number of iterations in the previous run
previousDuration time.Duration // total duration of the previous run
benchFunc func(b *B)
benchTime benchTimeFlag
bytes int64
missingBytes bool // one of the subbenchmarks does not have bytes set.
timerOn bool
showAllocResult bool
result BenchmarkResult
parallelism int // RunParallel creates parallelism*GOMAXPROCS goroutines
// The initial states of memStats.Mallocs and memStats.TotalAlloc.
startAllocs uint64
startBytes uint64
// The net total of this test after being run.
netAllocs uint64
netBytes uint64
// Extra metrics collected by ReportMetric.
extra map[string]float64
}
Как видите, тестирование.B Первый элемент также common структуру, поэтому он также имеет testing.T Для всех методов отчетности в , вы можете обратиться к пояснениям в предыдущей статье: Разработка через тестирование против. golang Модульное тестирование
Поскольку это стресс-тест производительности, статистика последовательного выполнения и время выполнения часто не являются тем методом тестирования, который нам нужен. Наблюдение за потреблением ресурсов посредством параллельного выполнения является лучшим методом тестирования. go test предоставляет метод b.RunParallel для реализации функции параллельного выполнения нескольких методов эталонного тестирования.
func BenchmarkTemplateParallel(b *testing.B) {
templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))
b.RunParallel(func(pb *testing.PB) {
// каждый goroutine Иметь свой собственный bytes.Buffer.
var buf bytes.Buffer
for pb.Next() {
// все goroutine Вместе, катаемся вместе, изучаем b.N Второсортный
buf.Reset()
templ.Execute(&buf, "World")
}
})
}
Тестовая функция, вызывающая метод b.RunParallel, будет запущена в отдельной горутине. Следует отметить, что три метода b.StartTimer, b.StopTime и b.ResetTimer будут влиять на все горутины, поэтому не вызывайте их в параллельных тестах.
Параллельность параллельных тестов контролируется переменной среды GOMAXPROCS, которая по умолчанию представляет собой количество ядер ЦП. Вы можете управлять параллелизмом с помощью метода b.SetParallelism перед запуском теста. Например, выполнение b.SetParallelism(2) означает, что параллелизм равен 2*GOMAXPROCS. При выполнении команды go test добавьте параметр -cpu, чтобы вывести подробную информацию о потреблении ресурсов процессора.
Помимо наблюдения за вызовами ЦП, нам часто также необходимо наблюдать за использованием памяти. Добавьте параметр -benchmem в команду go test, чтобы включить функцию статистики памяти для эталонного теста. Вы также можете вызвать функцию b.ReportAllocs до начала выполнения тестового примера. Преимущество этого метода в том, что он повлияет только на те функции, которые вам нужны:
func BenchmarkTmplExucte(b *testing.B) {
b.ReportAllocs()
templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))
b.RunParallel(func(pb *testing.PB) {
// Each goroutine has its own bytes.Buffer.
var buf bytes.Buffer
for pb.Next() {
// The loop body is executed b.N times total across all goroutines.
buf.Reset()
templ.Execute(&buf, "World")
}
})
}
Распечатано:
BenchmarkTmplExucte-4 2000000 898 ns/op 368 B/op 9 allocs/op
Указывает всего 2 000 000 выполнений со средним потреблением времени 898 наносекунд, каждое выполнение потребляет 368 байт памяти и всего 9 выделений памяти.
Представляем goroutine Что касается безопасности параллелизма, мы представили контент, связанный с тестированием безопасности параллелизма: goroutine Решение условий гонки в параллелизме
Добавив параметр -race в команду go test, вы сможете обнаружить возможные проблемы безопасности параллелизма на этапе тестирования. Ниже приведен типичный пример, небезопасный для параллелизма:
func TestParallelSafe(t *testing.T) {
a := 1
go func(){
a = 2
}()
a = 3
t.Logf("a is ", a)
time.Sleep(2 * time.Second)
}
Выполнение go test -race выведет:
runtime go test -race . a is 3 ================== WARNING: DATA RACE Write by goroutine 5: main.func·001() /data/test/race1.go:11 +0x3a Previous write by main goroutine: main.main() /data/test/race1.go:13 +0xe7 Goroutine 5 (running) created at: main.main() /data/test/race1.go:12 +0xd7 ================== Found 1 data race(s) exit status 66
Это покажет наличие состояния гонки. Однако следует отметить, что только код, покрытый тест-кейсами, может успешно обнаружить конкуренцию, поэтому очень важно обеспечить покрытие тест-кейсов.
Добавьте параметр -coverprofile в команду go test и укажите выходной файл для вывода отчета о покрытии тестами.