Перейти к основному содержимому

Маленькие правила, большая разница

Хорошие тесты следуют нескольким привычкам:

1. Понятные имена — test_greet_empty_name говорит, что сломалось, без открытия файла.
2. Одно поведение на тест — маленькие тесты указывают прямо на проблему.
3. Таблицы для множества случаев — один параметризованный тест вместо скопированных тестов.
4. Сообщения с полученным и ожидаемым значением — упавший тест должен объяснять себя сам.
5. Отдельные тесты, чтобы видеть всё; несколько assert в одном тесте, когда продолжать бессмысленно.
6. Запускайте тесты часто — после каждого небольшого изменения, а не один раз в конце.
7. Тесты живут рядом с кодом — в той же папке, с префиксом test_.


Сообщения об ошибках, которые помогают

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

Хорошая форма — func(input) = got; ожидалось want. Преобразование !r в f-строке выводит строки в кавычках, поэтому пропущенный пробел или пропущенная запятая сразу видны.

Сообщение со всей историей

greet возвращает неверное приветствие. Наше сообщение показывает вызов, полученное и ожидаемое значение, а pytest добавляет под ним своё сравнение двух строк — ошибка (не то слово, нет запятой и восклицательного знака) видна по одному выводу, без открытия кода.

Prompt
Напишите тестовый файл на Python, в котором функция greet возвращает неверное приветствие ('Hi Ana' вместо 'Hello, Ana!'), а сообщение assert сообщает вызов, полученное значение и ожидаемое значение, используя !r, чтобы строки выводились в кавычках. Покажите вывод упавшего теста pytest -v.
Вывод: полная программа на Python

Одно поведение на тест

У теста, который проверяет пять вещей, пять причин упасть — а его имя может описать только одну из них. Разделение по поведению делает каждый тест маленьким, а его имя честным. Здесь это важно вдвойне, потому что неудачный assert останавливает свой тест: пять проверок в одном тесте означают, что вы всегда видите только первую ошибку.

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

Два поведения, два теста

test_greet_name проверяет обычный случай, test_greet_empty — запасной вариант. Подробный вывод перечисляет их отдельно — ошибка указала бы ровно на одно поведение.

Prompt
Напишите тестовый файл на Python с функцией greet, которая приветствует по имени, а для пустого имени возвращает запасной вариант 'Hello, stranger!'. Напишите два отдельных узких теста, по одному на каждое поведение, с именами, которые говорят, что они проверяют. Покажите вывод успешного запуска pytest -v, где перечислены оба теста.
Вывод: полная программа на Python

Сколько протестировано: покрытие

Плагин pytest-cov (устанавливается командой pip install pytest-cov) измеряет, какую часть вашего кода тесты действительно выполняют. Запустите pytest --cov=., и после прогона тестов добавится таблица: сколько инструкций в каждом файле, сколько тесты пропустили и какой процент покрыт.

Это число — компас, а не цель: низкое значение показывает непротестированные пути — здесь тест проходит только по ветке mild, поэтому return для freezing и hot никогда не выполняются. 100% покрытия не доказывает, что код правильный, но непокрытые строки гарантированно не проверены.

Измеряем покрытие

У describe три ветки, тест проверяет одну. Отчёт насчитывает 8 инструкций, 2 пропущены, 75% покрыто — пропущены как раз return для freezing и hot. Тесты для холодной и жаркой ветки подняли бы это число.

Измеряется весь файл, включая тест, поэтому число не ниже: все строки самого теста были выполнены.

Prompt
Напишите тестовый файл на Python с функцией describe, которая в зависимости от температуры возвращает freezing, mild или hot, и одним тестом, который проверяет только ветку mild. Покажите вывод pytest --cov с количеством инструкций и процентом покрытия.
Вывод: полная программа на Python
Measure the coverage