Введение
Этот лабораторный практикум旨在演示单元测试和基准测试在编写规范的 Go 程序中的重要性。testing包提供了编写单元测试所需的工具,而go test命令则用于运行测试。
Тестирование и бенчмаркирование
Проблема, которую необходимо решить в этом лабораторном практикуме, — это протестировать и провести бенчмарк простой реализации функции нахождения минимального целого числа под названием IntMin.
- Необходимо импортировать пакет
testing. - Функция
IntMinдолжна принимать два целочисленных параметра и возвращать целое число. - Функция
TestIntMinBasicдолжна тестировать функциюIntMinдля базовых значений входных данных. - Функция
TestIntMinTableDrivenдолжна тестировать функциюIntMinв табличном стиле. - Функция
BenchmarkIntMinдолжна провести бенчмарк функцииIntMin.
## Запустить все тесты в текущем проекте в подробном режиме.
## Запустить все бенчмарки в текущем проекте. Все тесты
## выполняются перед бенчмарками. Флаг `bench` фильтрует
## имена функций бенчмарков с помощью регулярного выражения.
Ниже представлен полный код:
// Юнит-тестирование является важной частью написания
// принципиальных Go-программ. Пакет `testing`
// предоставляет инструменты, которые нам нужны для написания
// юнит-тестов, а команда `go test` запускает тесты.
// В целях демонстрации этот код находится в пакете
// `main`, но это может быть любой пакет. Код для тестирования
// обычно находится в том же пакете, что и код, который он тестирует.
package main
import (
"fmt"
"testing"
)
// Мы будем тестировать эту простую реализацию
// нахождения минимального целого числа. Обычно код,
// который мы тестируем, находится в исходном файле,
// названном, например, `intutils.go`, а тестовый файл
// для него будет называться `intutils_test.go`.
func IntMin(a, b int) int {
if a < b {
return a
}
return b
}
// Тест создается путем написания функции с именем,
// начинающимся с `Test`.
func TestIntMinBasic(t *testing.T) {
ans := IntMin(2, -2)
if ans!= -2 {
// `t.Error*` сообщит о неудаче теста, но продолжит
// выполнение теста. `t.Fatal*` сообщит о неудаче теста
// и немедленно остановит тест.
t.Errorf("IntMin(2, -2) = %d; want -2", ans)
}
}
// Пишение тестов может быть повторяющимся процессом, поэтому
// обычно используется *табличный стиль*, где входные данные
// теста и ожидаемые выходные данные перечислены в таблице,
// и единственный цикл проходит по ним и выполняет логику теста.
func TestIntMinTableDriven(t *testing.T) {
var tests = []struct {
a, b int
want int
}{
{0, 1, 0},
{1, 0, 0},
{2, -2, -2},
{0, -1, -1},
{-1, 0, -1},
}
for _, tt := range tests {
// t.Run позволяет запускать "подтесты", по одному для
// каждой записи таблицы. Они отображаются отдельно
// при выполнении `go test -v`.
testname := fmt.Sprintf("%d,%d", tt.a, tt.b)
t.Run(testname, func(t *testing.T) {
ans := IntMin(tt.a, tt.b)
if ans!= tt.want {
t.Errorf("got %d, want %d", ans, tt.want)
}
})
}
}
// Бенчмарк-тесты обычно находятся в файлах `_test.go` и
// именуются с префиксом `Benchmark`. Выполняющийся тестер
// несколько раз запускает каждую функцию бенчмарка,
// увеличивая `b.N` на каждой итерации, пока не получит
// точную меру.
func BenchmarkIntMin(b *testing.B) {
// Обычно бенчмарк запускает функцию, которую мы
// бенчмаркируем, в цикле `b.N` раз.
for i := 0; i < b.N; i++ {
IntMin(1, 2)
}
}
Резюме
Этот лабораторный практикум показал, как писать юнит-тесты и функции бенчмарка с использованием пакета testing в Go. Функция TestIntMinBasic тестировала функцию IntMin для базовых значений входных данных, в то время как функция TestIntMinTableDriven использовала табличный стиль для тестирования функции IntMin. Функция BenchmarkIntMin провела бенчмарк функции IntMin, чтобы измерить ее производительность.