Перейти до основного вмісту
Модуль 9 · Урок 1 із 541/50 у курсі~12 min
Модульні уроки (1/5)

Пакет «тестування».

У Go тести є частиною stdlib: немає зовнішньої бібліотеки, немає фреймворку для налаштування. Усе, що вам потрібно, це файл *_test.go поруч із кодом, кілька функцій TestXxx та команда go test.

Основні умовні позначення

  • Тестові файли називаються <something>_test.go і знаходяться в тому самому пакеті, що й код, який вони перевіряють (або в пакеті <name>_test для «тестів чорної скриньки»).
  • Тестові функції мають точний підпис: func TestXxx(t *testing.T), де Xxx починається з великої літери.
  • Ви імпортуєте testing із stdlib.
  • Ні assertEquals: ви використовуєте if got != want { t.Errorf(...) } з дієсловами fmt.
Go
// math.go
package math

func Sum(a, b int) int { return a + b }

// math_test.go
package math

import "testing"

func TestSum(t *testing.T) {
    got := Sum(2, 3)
    if got != 5 {
        t.Errorf("Sum(2,3) = %d; voglio %d", got, 5)
    }
}

Запустіть його за допомогою:

Bash
go test ./...        # all packages in the module
go test -v ./pkg     # verbose: prints test names
go test -run TestSum  # only tests matching the regex

t.Error проти t.Fatal

Ось два основних дієслова, які сигналізують про невдачу:

МетодЕфект
t.Log(args...)Реєструється, але не виходить з ладу (видно лише з -v або в разі збою).
t.Error(args...)Журнали, позначає FAIL, продовжує тестову функцію.
t.Errorf(fmt, ...)Як Error з форматуванням.
t.Fatal(args...)Журнали, позначає FAIL, зупиняє тест (викликає runtime.Goexit).
t.Fatalf(fmt, ...)Як Fatal з форматуванням.

Емпіричне правило: використовуйте Fatal, коли продовження не має сенсу (наприклад, невдале налаштування, неминуче розіменування нульового вказівника); інакше Error, що дозволяє побачити всі помилки за один прогін.

Go
func TestOpen(t *testing.T) {
    f, err := os.Open("fixtures/sample.txt")
    if err != nil {
        t.Fatal(err) // if it doesn't open, the next steps would fail on nil
    }
    defer f.Close()
    // ... assert on content with t.Errorf
}

Налаштування та демонтаж за допомогою t.Cleanup

Щоб звільнити ресурси в кінці тесту (або підтесту), використовуйте t.Cleanup замість defer:

Go
func TestDB(t *testing.T) {
    db := newTestDB(t)
    t.Cleanup(func() { db.Close() })
    // ... test
}

Перевага перед defer: помічник, який створює db, може зареєструвати очищення всередині, тому абонентам не потрібно його запам’ятовувати.

Тестові помічники

Метод t.Helper() позначає функцію як «допоміжну»: коли тест не вдається, трасування стека пропускає допоміжну функцію та вказує безпосередньо на виклик:

Go
func mustParseInt(t *testing.T, s string) int {
    t.Helper()
    n, err := strconv.Atoi(s)
    if err != nil {
        t.Fatalf("parse %q: %v", s, err)
    }
    return n
}

вправи

вправи#go.m9.l1.e1
Спроби: 0Завантаження…

Визначте функцію TestSum, яка перевіряє Sum(2,3) == 5 за допомогою t.Errorf із відформатованим повідомленням.

Завантаження редактора…

Рішення доступне після 3 спроб

вправи#go.m9.l1.e2
Спроби: 0Завантаження…

У TestDiv використовуйте t.Fatal, щоб негайно зупинити тест, якщо Div повертає неочікуване значення.

Завантаження редактора…

Рішення доступне після 3 спроб

Quiz#go.m9.l1.e3
Готовий

У чому принципова різниця між t.Error і t.Fatal?

Go
if err != nil {
  t.???(err)
}
Варіанти відповідей