Показаны сообщения с ярлыком юнит-тесты в Go. Показать все сообщения
Показаны сообщения с ярлыком юнит-тесты в Go. Показать все сообщения

четверг, 4 июня 2020 г.

Пакет testing в Golang

Пакет testing обеспечивает поддержку автоматического тестирования пакетов Go. Он предназначен для использования совместно с командой "go test", которая автоматизирует выполнение любой функции формы

func TestXxx(*testing.T)

где Xxx не начинается со строчной буквы. Имя функции служит для идентификации процедуры тестирования.

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

Чтобы написать новый набор тестов, создайте файл, имя которого заканчивается _test.go и содержит функции TestXxx, как описано здесь. Поместите файл в тот же пакет, что и тестируемый. Файл будет исключен из обычных сборок пакетов, но будет включен при запуске команды "go test".

Простая тестовая функция выглядит так:

func TestAbs(t *testing.T) {
    got := Abs(-1)
    if got != 1 {
        t.Errorf("Abs(-1) = %d; want 1", got)
    }
}

Бенчмарки

Функции формы

func BenchmarkXxx(*testing.B)

считаются бенчмарками и выполняются командой "go test", если указан флаг -bench. Тесты запускаются последовательно.

Пример бенчмарк функции выглядит следующим образом:

func BenchmarkHello(b *testing.B) {
    for i := 0; i < b.N; i++ {
        fmt.Sprintf("hello")
    }
}

Бенчмарк функция должна запускать целевой код b.N раз. Во время выполнения бенчмарка b.N корректируется до тех пор, пока функция бенчмарка не продержится достаточно долго, чтобы быть надежно синхронизированной. Вывод

BenchmarkHello    10000000    282 ns/op

означает, что цикл выполнялся 10000000 раз со скоростью 282 нс на цикл.

Если перед запуском бенчмарка требуется дорогостоящая настройка, таймер может быть сброшен:

func BenchmarkBigLen(b *testing.B) {
    big := NewBig()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        big.Len()
    }
}

Если бенчмарку нужно тестировать производительность в параллельном режиме, он может использовать вспомогательную функцию RunParallel; такие тесты предназначены для использования с флагом go test -cpu:

func BenchmarkTemplateParallel(b *testing.B) {
    templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))
    b.RunParallel(func(pb *testing.PB) {
        var buf bytes.Buffer
        for pb.Next() {
            buf.Reset()
            templ.Execute(&buf, "World")
        }
    })
}

Примеры (Examples)

Пакет также запускается и проверяет пример кода. Функции example могут включать заключительную строку комментария, которая начинается с "Output:" и сравнивается со стандартным выводом функции при выполнении тестов. (Сравнение игнорирует начальные и конечные пробелы.) Это примеры example:

func ExampleHello() {
    fmt.Println("hello")
    // Output: hello
}

func ExampleSalutations() {
    fmt.Println("hello, and")
    fmt.Println("goodbye")
    // Output:
    // hello, and
    // goodbye
}

Префикс комментария "Unordered output:" похож на "Output:", но соответствует любому порядку строк:

func ExamplePerm() {
    for _, value := range Perm(5) {
        fmt.Println(value)
    }
    // Unordered output: 4
    // 2
    // 1
    // 3
    // 0
}

Example функции без выходных комментариев компилируются, но не выполняются.

Соглашение об именах для объявления примеров для пакета, функции F, типа T и метода M для типа T:

func Example() { ... }
func ExampleF() { ... }
func ExampleT() { ... }
func ExampleT_M() { ... }

Несколько примеров функций для пакета/типа/функции/метода могут быть предоставлены путем добавления отдельного суффикса к имени. Суффикс должен начинаться со строчной буквы.

func Example_suffix() { ... }
func ExampleF_suffix() { ... }
func ExampleT_suffix() { ... }
func ExampleT_M_suffix() { ... }

Весь тестовый файл представлен в качестве примера (example), когда он содержит одну example функцию, по крайней мере, одну другую функцию, тип, переменную или объявление константы, и не содержит тестовых или бенчмарк функций.

Пропуски

Тесты или бенчмарки могут быть пропущены во время выполнения с помощью вызова Skip метода *T или *B:

func TestTimeConsuming(t *testing.T) {
    if testing.Short() {
        t.Skip("пропуск теста в сокращенном режиме.")
    }
    ...
}

Субтесты и суб-бенчмарки

Методы Run для T и B позволяют определять субтесты и суб-бенчмарки без необходимости определять отдельные функции для каждого. Это позволяет использовать табличные бенчмарки и создавать иерархические тесты. Это также предоставляет возможность поделиться общим кодом установки и удаления (очистки):

func TestFoo(t *testing.T) {
    // установочный код
    t.Run("A=1", func(t *testing.T) { ... })
    t.Run("A=2", func(t *testing.T) { ... })
    t.Run("B=1", func(t *testing.T) { ... })
    // код очистки
}

Каждый субтест и суб-бенчмарк имеет уникальное имя: сочетание имени теста верхнего уровня и последовательности имен, передаваемых в Run, разделенных косой чертой, с необязательным конечным порядковым номером для устранения неоднозначности.

Аргумент для флагов командной строки -run и -bench - это нефиксированное регулярное выражение, которое соответствует имени теста. Для тестов с несколькими элементами, разделенными слешем, такими как субтесты, аргумент сам разделен слэшем, а выражения по очереди соответствуют каждому элементу имени. Поскольку оно не занято, пустое выражение соответствует любой строке. Например, использование "соответствия" ("matching") означает "чье имя содержит":

go test -run ''      # запускает все тесты
go test -run Foo     # запускает верхнеуровневые тесты соотвествующие "Foo", такие как "TestFooBar".
go test -run Foo/A=  # запускает верхнеуровневые тесты соотвествующие "Foo", запускает субтесты соотвествующие "A=".
go test -run /A=1    # запускает все верхнеуровневые тесты, запускает субтесты соотвествующие "A=1".

Субтесты также могут быть использованы для контроля параллелизма. Родительский тест будет завершен только после завершения всех его субтестов. В этом примере все тесты выполняются параллельно друг другу и только друг с другом, независимо от других тестов верхнего уровня, которые могут быть определены:

func TestGroupedParallel(t *testing.T) {
    for _, tc := range tests {
        tc := tc // захватить переменную диапазона
        t.Run(tc.Name, func(t *testing.T) {
            t.Parallel()
            ...
        })
    }
}

Детектор гонки убивает программу, если она превышает 8192 конкурентных goroutine, поэтому будьте осторожны при выполнении параллельных тестов с установленным флагом -race.

Выполнение не возвращается до тех пор, пока параллельные субтесты не будут завершены, предоставляя способ очистки после группы параллельных тестов:

func TestTeardownParallel(t *testing.T) {
    // Этот Run не вернется, пока не завершатся параллельные тесты.
    t.Run("group", func(t *testing.T) {
        t.Run("Test1", parallelTest1)
        t.Run("Test2", parallelTest2)
        t.Run("Test3", parallelTest3)
    })
    // код очистки
}

Main

Иногда тестовой программе необходимо выполнить дополнительную настройку или демонтаж до или после тестирования. Иногда тесту также необходимо контролировать, какой код выполняется в основном (main) потоке. Для поддержки этих и других случаев, если тестовый файл содержит функцию:

func TestMain(m *testing.M)

тогда сгенерированный тест вызовет TestMain(m) вместо непосредственного запуска тестов. TestMain работает в основной программе и может выполнять любые настройки и разборки, необходимые для вызова m.Run. Затем он должен вызвать os.Exit с результатом m.Run. Когда вызывается TestMain, flag.Parse не был запущен. Если TestMain зависит от флагов командной строки, включая флаги пакета тестирования, он должен явно вызывать flag.Parse.

Простая реализация TestMain:

func TestMain(m *testing.M) {
    // вызываем flag.Parse() здесь, 
    // если TestMain использует флаги
    os.Exit(m.Run())
}


Читайте также:


четверг, 7 мая 2020 г.

Табличные юнит-тесты в Golang

Вот код, который мы хотим протестировать.

package search

// Find возвращает наименьший индекс i, 
// при котором x <= a[i].
// Если такого индекса нет, он возвращает len(a).
// Срез должен быть отсортирован в порядке возрастания.
func Find(a []int, x int) int {
    switch len(a) {
    case 0:
        return 0
    case 1:
        if x <= a[0] {
            return 0
        }
        return 1
    }
    mid := len(a) / 2
    if x <= a[mid-1] {
        return Find(a[:mid], x)
    }
    return mid + Find(a[mid:], x)
}

  • Поместите тестовый код в файл, имя которого заканчивается на _test.go.
  • Напишите функцию TestXXX с единственным аргументом типа *testing.T. Фреймворк тестирования запускает каждую такую ​​функцию.
  • Чтобы указать неудачный тест, вызовите функцию отказа, такую ​​как t.Errorf.

package search

import "testing"

var tests = []struct {
    a   []int
    x   int
    exp int
}{
    {[]int{}, 1, 0},
    {[]int{1, 2, 3, 3}, 0, 0},
    {[]int{1, 2, 3, 3}, 1, 0},
    {[]int{1, 2, 3, 3}, 2, 1},
    {[]int{1, 2, 3, 3}, 3, 3}, // ошибочный тестовый кейс
    {[]int{1, 2, 3, 3}, 4, 4},
}

func TestFind(t *testing.T) {
    for _, e := range tests {
        res := Find(e.a, e.x)
        if res != e.exp {
            t.Errorf("Find(%v, %d) = %d, expected %d",
                e.a, e.x, res, e.exp)
        }
    }
}

Запустите тесты с помощью go test.

$ go test
--- FAIL: TestFind (0.00s)
    search_test.go:22: Find([1 2 3 3], 3) = 2, expected 3
FAIL
exit status 1
FAIL    .../search  0.001s


Читайте также:


суббота, 13 июля 2019 г.

Функции тестирования в Golang

Команда 'go test' предполагает найти функции test, benchmark и example в файлах *_test.go, соответствующих тестируемому пакету.

Тестовая функция называется TestXxx (где Xxx не начинается со строчной буквы) и должна иметь сигнатуру,

func TestXxx(t *testing.T) { ... }

Контрольная функция называется BenchmarkXxx и должна иметь сигнатуру,

func BenchmarkXxx(b *testing.B) { ... }

Функция example похожа на функцию test, но вместо использования *testing.T для сообщения об успехе или неудаче выводит вывод в os.Stdout. Если последний комментарий в функции начинается с "Output:", то результат сравнивается точно с комментарием (см. Примеры ниже). Если последний комментарий начинается с "Unordered output:", то результат сравнивается с комментарием, однако порядок строк игнорируется. Пример без такого комментария компилируется, но не выполняется. Пример без текста после "Output:" компилируется, выполняется и, как ожидается, не будет производить вывод.

Godoc отображает тело ExampleXxx, чтобы продемонстрировать использование функции, константы или переменной Xxx. Пример метода M с типом получателя T или *T называется ExampleT_M. Может быть несколько примеров для данной функции, константы или переменной, отличающихся завершающим _xxx, где xxx - суффикс, не начинающийся с заглавной буквы.

Вот пример example:

func ExamplePrintln() {
    Println("The output of\nthis example.")
    // Output: The output of
    // this example.
}

Вот еще один пример, где порядок вывода игнорируется:

func ExamplePerm() {
    for _, value := range Perm(4) {
        fmt.Println(value)
    }

    // Unordered output: 4
    // 2
    // 1
    // 3
    // 0
}

Весь тестовый файл представлен в качестве example, когда он содержит одну example функцию, по крайней мере, одну другую функцию, тип, переменную или объявление константы, и не содержит test или benchmark функций.


Читайте также:


четверг, 11 июля 2019 г.

Флаги тестирования в Golang

Команда 'go test' принимает флаги, которые применяются к самому 'go test', и флаги, которые применяются к полученному бинарному файлу теста.

Несколько флагов управляют профилированием и записывают профиль выполнения, подходящий для "go tool pprof"; запустите "go tool pprof -h" для получения дополнительной информации. Параметры --alloc_space, --alloc_objects и --show_bytes в pprof управляют представлением информации.

Следующие флаги распознаются командой 'go test' и контролируют выполнение любого теста:

-bench regexp

Запускать только те эталонные тесты (benchmarks), которые соответствуют регулярному выражению. По умолчанию эталонные тесты не запускаются. Чтобы запустить все эталонные тесты, используйте '-bench .' или '-bench=.'. Регулярное выражение разделяется символами косой чертой без скобок (/) в последовательности регулярных выражений, и каждая часть идентификатора эталонного теста должна соответствовать элементу в последовательности, если есть. Возможные родители соотвествий запускаются с b.N=1, чтобы идентифицировать нижележащие эталонные тесты. Например, учитывая -bench =X/Y, запускаются эталонные тесты верхнего уровня, соответствующие X с b.N=1, чтобы найти любые нижележащие эталонные тесты, соответствующие Y, которые потом запускаются полностью.


-benchtime t

Запустить достаточно итераций каждого эталонного теста, чтобы взять t, указанный как time.Duration (например, -benchtime 1h30s). По умолчанию это 1 секунда (1s). Специальный синтаксис Nx означает запуск теста N раз (например, -benchtime 100x).


-count n

Запустите каждый тест и эталонный тест n раз (по умолчанию 1). Если установлена опция -cpu, запускать n раз для каждого значения GOMAXPROCS. Примеры всегда запускаются один раз.


-cover

Включить анализ покрытия. Обратите внимание, потому что покрытие работает, аннотируя исходный код перед компиляцией, компиляция и ошибки тестирования с включенным покрытием могут сообщать номера строк, которые не соответствуют оригинальному исходному коду.


-covermode set,count,atomic

Установить режим анализа покрытия для пакета/пакетов, которые тестируются. По умолчанию установлено "set", если не включена опция -race, в этом случае это "atomic".
Значения:
set: bool: это утверждение выполняется?
count: int: сколько раз выполняется это утверждение?
atomic: int: то же самое что count, но корректный в многопоточных тестах; значительно более затратный.
Включает флаг -cover.


-coverpkg pattern1,pattern2,pattern3

Применить анализ покрытия в каждом тесте к пакетам, соответствующим шаблонам (patterns). По умолчанию для каждого теста анализируется только тестируемый пакет. Смотрите 'go help packages' для описания шаблонов пакетов.
Включает флаг -cover.


-cpu 1,2,4

Укажите список значений GOMAXPROCS, для которых тесты или эталонные тесты должны быть выполнены. По умолчанию используется текущее значение GOMAXPROCS.


-failfast

Не запускать новые тесты после первого неудачного теста.


-list regexp

Перечислите тесты, эталонные тесты (benchmarks) или примеры, соответствующие регулярному выражению. Никаких тестов, эталонных тестов или примеров запускаться не будет. Это будет только список тестов верхнего уровня. Никакие субтесты или суб-эталонные тесты не будут показаны.


-parallel n

Разрешить параллельное выполнение тестовых функций, которые вызывают t.Parallel. Значение этого флага - максимальное количество тестов для одновременного запуска; по умолчанию для него установлено значение GOMAXPROCS. Обратите внимание, что -parallel применяется только в одном бинарном тесте. Команда go test может запускать тесты для разных пакетов параллельно, в соответствии с настройкой флага -p (см. go help build).


-run regexp

Запускайте только те тесты и примеры, которые соответствуют регулярному выражению. Для тестов регулярное выражение разделяется символами косой черты без скобок (/) в последовательности регулярных выражений, и каждая часть идентификатора теста должна совпадать с соответствующим элементом в последовательности, если есть. Обратите внимание, что возможные родители соответствий тоже запускаются, так что -run =X/Y соответствует, запускает и сообщает результаты всех тестов, соответствующих X, даже без тестов, соответствующих Y, потому что он должен запустить их, чтобы искать эти под-тесты.


-short

Сообщить длительным тестам, чтобы они сократили свое время выполнения. Флаг выключен по умолчанию, но установлен во время all.bash, чтобы установка дерева Go могла выполнять проверку работоспособности, но не тратить время на прохождение исчерпывающих длительных тестов.


-timeout d

Если тестовый бинарный файл работает дольше, чем продолжительность d, запускать panic. Если d равно 0, тайм-аут отключен. По умолчанию 10 минут (10m).


-v

Подробный вывод: протоколировать все тесты по мере их запуска. Также распечатать весь текст из вызовов Log и Logf, даже если тест пройден успешно.


-vet list

Сконфигурировать вызов "go vet" во время "go test" чтобы использовать разделенный запятыми список проверок. Если список пуст, "go test" запускает "go vet" с курируемым списком проверок, считаемых всегда заслуживающими внимания. Если list равен "off", "go test" вообще не запускает "go vet".


Следующие флаги также распознаются 'go test' и могут использоваться для профилирования тестов во время выполнения:

-benchmem

Распечатать статистику распределения памяти для тестов.


-blockprofile block.out

Записать профиль блокировки goroutine в указанный файл когда все тесты завершены. Записывает тестовый бинарный файл как делает флаг -c.


-blockprofilerate n

Контролировать детализацию профилей блокировки goroutine посредством вызова runtime.SetBlockProfileRate с n. См. 'go doc runtime.SetBlockProfileRate'. Целью профилировщика является выборка в среднем одного блокирующего события каждые n наносекунд, которые программа тратит на блокировку. По умолчанию, если -test.blockprofile установлен без этого флага, все события блокировки записаны, эквивалентно -test.blockprofilerate=1.


-coverprofile cover.out

Записать профиль покрытия в файл после того, как все тесты пройдены.
Включает флаг -cover.


-cpuprofile cpu.out

Записать профиль CPU в указанный файл перед выходом. Записывает тестовый бинарный файл как делает флаг -c.


-memprofile mem.out

Записать профиль распределения в файл после того, как все тесты пройдены. Записывает тестовый бинарный файл как флаг -c.


-memprofilerate n

Включить более точные (и дорогие) профили выделения памяти установкой runtime.MemProfileRate. Смотрите 'go doc runtime.MemProfileRate'. Чтобы профилировать все распределения памяти, используйте -test.memprofilerate=1.


-mutexprofile mutex.out

Записать конфликтный профиль мьютекса в указанный файл когда все тесты завершены. Записывает тестовый бинарный файл как флаг -c.


-mutexprofilefraction n

Образец 1 в n стека следов goroutines, содержащих утвержденный мьютекс.


-outputdir directory

Поместить выходные файлы из профилирования в указанный каталог, по умолчанию каталог, в котором запущен "go test".


-trace trace.out

Записать трассировку выполнения в указанный файл перед выходом.


Каждый из этих флагов также распознается с помощью необязательного 'test.' префикса, как в -test.v. Однако при непосредственном вызове сгенерированного тестового бинарного файла (результат 'go test -c') префикс обязателен.

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

Например, команда

go test -v -myflag testdata -cpuprofile=prof.out -x

скомпилирует тестовый бинарный файл, а затем запустит его как

pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out

(Флаг -x удален, потому что он применяется только к выполнению команды go, а не к самому тесту.)

Флаги теста, которые генерируют профили (кроме покрытия), также оставляют тестовый бинарный файл в pkg.test для использования при анализе профилей.

Когда 'go test' запускает тестовый бинарный файл, он делает это из каталога исходного кода соответствующего пакета. В зависимости от теста может потребоваться сделать то же самое при непосредственном вызове сгенерированного тестового бинарного файла.

Список пакетов командной строки, если он присутствует, должен отображаться перед любым флагом, неизвестным команде go test. Продолжая приведенный выше пример, список пакетов должен отображаться перед -myflag, но может отображаться с любой стороны от -v.

Когда 'go test' выполняется в режиме списка пакетов, 'go test' кэширует успешные результаты тестирования пакета, чтобы избежать ненужного повторного запуска тестов. Чтобы отключить тестовое кэширование, используйте любой тестовый флаг или аргумент, кроме кешируемых флагов. Идиоматический способ явного отключения кэширования тестов - использовать -count=1.

Чтобы аргумент для тестового бинарного файла не интерпретировался как известный флаг или имя пакета, используйте параметр -args (см. go help test), который передает оставшуюся часть командной строки в тестовый бинарный файл без интерпретации и не измененной.

Например, команда

go test -v -args -x -v

скомпилирует тестовый бинарный файл, а затем запустит его как

pkg.test -test.v -x -v

Так же,

go test -args math

скомпилирует тестовый бинарный файл, а затем запустит его как

pkg.test math

В первом примере -x и второй -v передаются в тестовый бинарный файл без изменений и не влияют на саму команду go. Во втором примере аргумент math передается в тестовый бинарный файл, а не интерпретируется как список пакетов.


Читайте также:


воскресенье, 30 июня 2019 г.

Команды go: go test, тестировать пакеты

Использование:

go test [build/test flags] [packages] [build/test flags & test binary flags]

go test автоматизирует тестирование пакетов, названных путями импорта. Он печатает резюме результатов теста в формате:

ok   archive/tar   0.011s
FAIL archive/zip   0.022s
ok   compress/gzip 0.033s
...

с последующим подробным выводом для каждого неудачного пакета.

go test перекомпилирует каждый пакет вместе с любыми файлами с именами, соответствующими шаблону файла *_test.go. Эти дополнительные файлы могут содержать функции тестирования, эталонные (benchmark) функции и примеры функций. Смотрите 'go help testfunc' для более подробной информации. Каждый перечисленный пакет вызывает выполнение отдельного тестового бинарного файла. Файлы, имена которых начинаются с "_" (включая "_test.go") или "." игнорируются

Тестовые файлы, которые объявляют пакет с суффиксом "_test", будут скомпилированы как отдельный пакет, а затем связаны и запущены с основным тестовым бинарным файлом.

Инструмент go игнорирует каталог с именем "testdata", делая его доступным для хранения вспомогательных данных, необходимых для тестов.

В рамках создания бинарного теста go test выполняет go vet для пакета и его исходных файлов для выявления значительных проблем. Если go vet обнаружит какие-либо проблемы, go test сообщит их и не запустит бинарный файл теста. Используется только подмножество с высокой достоверностью проверок по умолчанию. Это подмножество: 'atomic', 'bool', 'buildtags', 'nilfunc' и 'printf'. Вы можете просмотреть документацию для этих и других vet тестов через "go doc cmd/vet". Чтобы отключить запуск go vet, используйте флаг -vet=off.

Все выходные данные теста и итоговые строки выводятся на стандартный вывод команды go, даже если тест выводит их со своей собственной стандартной ошибкой. (Стандартная ошибка команды go зарезервирована для ошибок печати при построении тестов.)

Go test выполняется в двух разных режимах:

Первый, называемый режимом локального каталога, возникает, когда go test вызывается без аргументов пакета (например, 'go test' или 'go test -v'). В этом режиме go test компилирует исходные коды пакетов и тесты, найденные в текущем каталоге, а затем запускает полученный тестовый бинарный файл. В этом режиме кэширование (обсуждается ниже) отключено. После того, как пакетный тест завершится, go test напечатает итоговую строку, показывающую статус теста ('ok' или 'FAIL'), имя пакета и истекшее время.

Второй, называемый режимом списка пакетов, возникает, когда go test вызывается с явными аргументами пакета (например, 'go test math', 'go test ./...' и даже 'go test .'). В этом режиме go test скомпилирует и протестирует каждый из пакетов, перечисленных в командной строке. Если пакетный тест пройден, go test печатает только последнюю итоговую строку 'ok'. Если пакетный тест не пройден, go test распечатывает полный тестовый вывод. Если вызывается с флагом -bench или -v, go test печатает полный вывод даже для прохождения пакетных тестов, чтобы отобразить запрошенные результаты тестов или подробное ведение журнала.

Только в режиме списка пакетов, go test кэширует успешные результаты тестирования пакета, чтобы избежать ненужного повторного запуска тестов. Когда результаты теста могут быть восстановлены из кэша, go test перезапустит предыдущий вывод вместо повторного запуска тестового бинарного файла. Когда это происходит, go test печатает '(cached)' вместо истекшего времени в итоговой строке.

Правило совпадения в кеше заключается в том, что в прогоне используется один и тот же тестовый бинарный файл, а флаги в командной строке целиком исходят из ограниченного набора "кэшируемых" ('cacheable') тестовых флагов, определенных как -cpu, -list, -parallel, -run, -short, и -v. Если запуск go test имеет какие-либо тестовые или не тестовые флаги вне этого набора, результат не кэшируется. Чтобы отключить кэширование тестов, используйте любой тестовый флаг или аргумент, кроме кешируемых флагов. Идиоматический способ явного отключения кэширования тестов - использовать -count=1. Тесты, которые открывают файлы внутри корня исходного кода пакета (обычно $GOPATH) или которые обращаются к переменным среды, соответствуют только будущим прогонам, в которых файлы и переменные среды не изменяются. Кэшированный результат теста обрабатывается как выполняющийся в кратчайшие сроки, поэтому успешный результат теста пакета будет кэшироваться и использоваться повторно независимо от значения параметра -timeout.

В дополнение к флагам сборки, флаги, обрабатываемые самим 'go test':

-args
    Передать остаток от командной строки (все после -args)
    бинарному тесту, без интерпретации и без изменений.
    Поскольку этот флаг потребляет оставшуюся часть командной строки,
    список пакетов (если имеется) должен появляться перед этим флагом.

-с
    Скомпилировать тестовый бинарный файл в pkg.test, но не запускать его
    (где pkg - последний элемент пути импорта пакета).
    Имя файла можно изменить с помощью флага -o.

-exec xprog
    Запустить тестовый бинарный файл с помощью xprog. Поведение такое же, как
    в 'go run'. Смотрите подробности в 'go help run'.

-i
    Установить пакеты, которые являются зависимостями теста.
    Не запускать тест.

-json
    Преобразовать выходные данные теста в формат JSON, подходящий для автоматической обработки.
    Смотрите 'go doc test2json' для деталей кодирования.

-o file
    Скомпилировать бинарный файл теста в указанный файл.
    Тест все еще выполняется (если не указано -c или -i).

Бинарный файл теста также принимает флаги, которые управляют выполнением теста; эти флаги также доступны в 'go test'. Смотрите 'go help testflag' для подробностей.

Для получения дополнительной информации о флагах сборки см. go help build. Подробнее об указании пакетов см. go help packages.

Смотрите также: go build, go vet.


Читайте также:


воскресенье, 17 марта 2019 г.

Go Code Review Comments: Полезные падения тестов

Тесты должны падать с полезными сообщениями, в которых говорится, что было не так, с какими вводными данными, что на самом деле было получено и что ожидалось. Может быть заманчиво написать кучу помощников assertFoo, но убедитесь, что ваши помощники выдают полезные сообщения об ошибках. Предположите, что человек, отлаживающий ваш упавший тест - это не вы и не ваша команда. Типичный Go тест проходит не так, как следующий:

if got != tt.want {
    t.Errorf("Foo(%q) = %d; want %d", tt.in, got, tt.want) 
    // или Fatalf, 
    // если тест не может тестировать что-либо далее 
    // этой точки
}

Обратите внимание, на порядок актуальный != ожидаемый, и сообщение также использует этот порядок. Некоторые тестовые среды рекомендуют записывать их в обратном порядке: 0 != x, «ожидаемый 0, полученный x» и так далее. Go не использует такой подход.

Если вам кажется, что набирается много текста, вы можете написать табличный тест.

Еще одна распространенная техника устранения неоднозначности неудачных тестов - это использование тестового помощника (test helper) с разными вводными данными - оберните каждого вызывающего различной функцией TestFoo, таким образом тест будет завершаться неудачно с разным именем:

func TestSingleValue(t *testing.T) { testHelper(t, []int{80}) }
func TestNoValues(t *testing.T)    { testHelper(t, []int{}) }

В любом случае, на вас ложится обязанность написать полезное сообщение тому, кто будет отлаживать ваш код в будущем.


Читайте также:


вторник, 19 февраля 2019 г.

Go FAQ: Где вспомогательные функции для тестирования в Go?

Стандартный пакет testing Go позволяет легко создавать юнит-тесты, но в нем нет функций, предоставляемых в средах тестирования других языков, такие как функции утверждений (assert). Правильная обработка ошибок означает запуск других тестов после того, как один из них потерпел неудачу, поэтому человек, отлаживающий ошибку, получает полную картину того, что произошло не так. Для теста полезней сообщить, что isPrime дает неправильный ответ для 2, 3, 5 и 7 (или для 2, 4, 8 и 16), чем сообщить, что isPrime выдает неверный ответ для 2 и, следовательно, больше тестов не проводилось. Программист, который получает тестовый сбой, возможно, не знаком с кодом, который терпит неудачу. Время, потраченное на написание хорошего сообщения об ошибке, окупается позже, когда тесты не проходят.

С этим связано то, что рамки тестирования имеют тенденцию развиваться в мини-языки самостоятельно, с условными и контрольными и печатными механизмами, но у Go уже есть все эти возможности; зачем их воссоздавать? Мы бы лучше написали тесты на Go; это один язык, чтобы выучить и использовать - такой подход делает тесты простыми и понятными.

Если объем дополнительного кода, требующегося для записи хороших ошибок, кажется повторяющимся и избыточным, тест может работать лучше, если управляем таблицей, перебирая список входов и выходов, определенных в структуре данных (Go имеет отличную поддержку литералов структуры данных). Работа над написанием хорошего теста и хороших сообщений об ошибках будет амортизироваться в течение многих тестовых случаев. Стандартная библиотека Go полна иллюстративных примеров, таких как тесты форматирования для пакета fmt.


Читайте также:


Go FAQ: Как написать юнит-тест в Go?

Создайте новый файл, заканчивающийся на _test.go в том же каталоге, где и ваши исходные файлы пакета. Внутри этого файла import "testing" и напишите функции следующего вида:

func TestFoo(t *testing.T) {
    ...
}

Запустите go test в этом каталоге. Этот скрипт находит функции Test, создает тестовый бинарный файл и запускает его.


Читайте также: