Go: с нуля до своего блога Урок 10 из 50
Первый тест в Go: go test и файл _test.go
Десятый урок курса по Go. Проверка, которая остаётся: файл _test.go рядом с кодом, функция TestXxx и команда go test. Как читать провал — имя теста, файл, строка, «получили» и «ждали», — чем t.Errorf отличается от t.Fatalf и почему проверять надо края списка, а не его середину.
Зачем это нужно
Вы уже написали count и longer. Откуда вы знаете, что они верны? Запустили, посмотрели на вывод, кивнули. Такая проверка живёт одну минуту: поправите функцию через неделю — и проверять придётся заново, руками, и вы этого не сделаете.
Тест — та же самая проверка, только записанная. Её выполняет машина, и выполняет каждый раз.
Образ. Список проверок у пилота перед взлётом. Он не потому, что пилот забывчивый, а потому что память не растёт вместе с числом дел. Список растёт.
Сразу целиком
Новая папка, go mod init sabaq09. На этот раз файлов будет два. Первый — main.go, знакомая функция из прошлого урока:
package main
import "fmt"
func count(tags []string) map[string]int {
m := make(map[string]int)
for _, t := range tags {
m[t]++
}
return m
}
func main() {
fmt.Println(count([]string{"go", "веб", "go"}))
}
Второй — main_test.go, рядом, в той же папке:
package main
import "testing"
func TestCount(t *testing.T) {
got := count([]string{"go", "веб", "go"})
if got["go"] != 2 {
t.Errorf("go: получили %d, ждали 2", got["go"])
}
if len(got) != 2 {
t.Errorf("тегов: получили %d, ждали 2", len(got))
}
}
Прежде чем запускать — не заглядывая ниже, скажите вслух, что напечатает go test. Потом запустите и сверьте.
PASS
ok sabaq09
Время прогона в выдержках убрано: оно у всех своё.
Последнее число — сколько это заняло времени; у вас будет своё.
Разбор
Тест — это файл рядом с кодом
Имя обязано заканчиваться на _test.go. Это не соглашение об аккуратности, а правило языка: такие файлы Go собирает только при go test и не включает в готовую программу. Тестов можно писать сколько угодно и сколь угодно подробно — на размер программы, которую вы отдадите людям, они не влияют.
Образ. Строительные леса. Пока дом строят, по ним ходят каждый день; в готовый дом они не входят, и никто не удивляется, что их нет.
Пакет тот же самый — package main, — поэтому тест видит count напрямую, безо всякого подключения.
Как выглядит тест
func TestCount(t *testing.T) {
Три требования, и все три обязательны. Имя начинается с Test. Дальше идёт заглавная буква — TestCount, а не Testcount. И единственный параметр — t *testing.T.
t — это то, чем тест сообщает о провале. Звёздочку пока читайте как часть записи; в уроке про указатели разберём, что она значит.
Функция ничего не возвращает. Тест, который ничего не сказал, считается пройденным: молчание здесь означает «всё сошлось».
go test и go test -v
go test печатает итог: PASS или FAIL. Когда тестов станет много и захочется видеть каждый по имени, добавьте -v:
=== RUN TestCount
--- PASS: TestCount
PASS
ok sabaq09
Провал читается как отчёт
Сломайте нарочно: замените в первом сравнении 2 на 3 и поправьте текст сообщения. Запустите:
--- FAIL: TestCount
main_test.go:9: go: получили 2, ждали 3
main_test.go:12: тегов: получили 2, ждали 3
FAIL
Здесь есть всё, что нужно: какой тест упал, в каком файле и на какой строке, что получили и чего ждали. Поэтому в сообщении и пишут обе величины. Сообщение вида «не сработало» не говорит ничего и заставляет лезть в код руками.
Красный FAIL — не наказание, а отчёт. За время работы вы увидите его в сотни раз чаще, чем PASS.
t.Errorf и t.Fatalf
t.Errorf записывает провал и продолжает тест — потому вы и увидели сразу две строки. t.Fatalf записывает и останавливает его: до второй проверки дело не дойдёт.
Правило простое. Fatalf — когда дальше идти бессмысленно: нужного значения нет, и следующая строка всё равно упадёт. Errorf — во всех остальных случаях: чем больше расхождений покажет один запуск, тем меньше запусков понадобится.
Что проверять в первую очередь
Не середину, а края. Середина обычно работает у всех.
Для count края такие: пустой список, один элемент, все элементы одинаковые. Для longer из урока про срез — список, где не подходит ни один заголовок, и список, где подходят все.
Образ. Дорога. Машины съезжают не на середине полосы, а на обочине. Проверять надо обочину.
Краёв обычно три-четыре, и переписывать ради каждого целый if вы быстро устанете. Так и не делают: случаи складывают в один список и проходят по нему циклом, а каждый получает своё имя в отчёте. Называется это табличным тестом, и мы напишем его в уроке про тесты во второй раз — когда у вас появятся структуры, из которых такой список и собирают. Пока держите в голове, что один тест на функцию — начало, а не образец.
Почему это не двойная работа
Кажется, будто вы пишете одно и то же дважды. На самом деле — по-разному. В count вы описываете, как считать. В тесте — что должно получиться. Ошибка в способе не повторится в описании результата, и потому одно ловит другое.
А ещё тест — единственная проверка, которая не устаёт. Вы поправите функцию через месяц, забудете половину и запустите go test — он вспомнит за вас.
Карта урока
Скажите своими словами
Не подглядывая, ответьте вслух или на бумаге. Ответы — в конце урока.
- Почему файл теста обязан оканчиваться на
_test.go? Что от этого зависит? - Тест ничего не напечатал и ничего не вернул. Он прошёл или нет?
- В одном тесте четыре проверки, и вторая упала. Сколько сообщений вы увидите с
t.Errorfи сколько сt.Fatalf?
Задание
Обязательное. Возьмите функцию longer из урока про срез и напишите к ней тест. Проверьте два случая: список "Дала", "Шаңырақ", "Go", "Көш" при n = 3 должен дать два заголовка, а пустой список при любом n — ни одного. Запустите go test и добейтесь PASS.
По желанию.
- Сломайте
longerнарочно — например, поставьте>=вместо>— и убедитесь, что тест краснеет. Проверка, которая не умеет упасть, ничего не проверяет. - Запустите
go test -vи посмотрите на разницу. - Замените в своём тесте
t.Errorfнаt.Fatalfи сломайте обе проверки сразу. Сколько строк вы теперь видите?
Куда это встанет в блоге
Помните readingTime из урока про функции — ту, что считает время чтения? Ошибка в ней была бы тихой: на ровных 400 словах легко получить три минуты вместо двух, и никто не заметит, пока не сядет считать. Именно такие ошибки и ловит тест: он проверит 199, 200 и 201 слово за одну секунду, и так каждый раз.
Дальше тесты пойдут с вами по всему курсу. Полный урок о тестировании — с таблицей случаев и покрытием — будет позже, когда появятся структуры. Сегодняшнего хватает, чтобы проверять свои задания самому.
Соберите свой блог. В step-4 к тем же файлам добавился
main_test.go: проверки на края — ноль слов, ровно двести, двести один. Именно на них ломаются формулы вроде времени чтения.
Ответы
Показать ответы
- Потому что это правило языка, а не привычка. Файлы с таким окончанием собираются только командой
go testи не попадают в готовую программу, поэтому тесты не увеличивают то, что вы отдаёте людям. - Прошёл. Тест сообщает только о провале — через
t.Errorfилиt.Fatalf. Молчание означает, что всё сошлось. - С
t.Errorfвы увидите сообщения обо всех упавших проверках, потому что тест продолжается после каждой. Сt.Fatalf— только одно, про вторую: на ней тест остановится, и третья с четвёртой не выполнятся.
Источники
Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом
Комментарии (0)
Войдите, чтобы оставить комментарий →
Пока нет комментариев. Будьте первым.