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

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

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

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


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

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

assertSame сам печатает ожидаемое и фактическое значение в виде diff; необязательный аргумент с сообщением добавляет недостающую часть — какой вызов дал это значение.

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

greet возвращает неверное приветствие. В выводе о провале видно своё сообщение с названием вызова, а затем diff: ожидалось 'Hello, Ana!', фактически 'Hi Ana' — ошибка (не то слово, нет запятой и восклицательного знака) видна по одному только выводу, без открытия кода.

Prompt
Напиши файл теста PHPUnit, в котором функция greet возвращает неверное приветствие («Hi Ana» вместо «Hello, Ana!»), а тест сравнивает значения через assertSame, добавляя сообщение с названием вызова. Покажи вывод phpunit с провалившимся тестом и diff ожидаемого/фактического значения.
Вывод: PHP-скрипт

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

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

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

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

testGreetName проверяет обычный случай, testGreetEmpty — подстановку. Вывод --testdox перечисляет их отдельно — провал указал бы ровно на одно поведение.

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

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

PHPUnit умеет измерять, какие строки вашего кода тесты действительно выполняют. Для этого в PHP нужно расширение для покрытия — PCOV или Xdebug — и найденное расширение он сообщает в строке заголовка.

./vendor/bin/phpunit --coverage-filter . --coverage-text DescribeTest.php измеряет файлы в текущей папке и печатает отчёт после результата тестов.

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

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

У describeTemperature три ветки, тест задействует одну. Отчёт считает каждую исполняемую строку файла — включая строку самого тестового метода — и сообщает Lines: 66.66% (4/6): две непокрытые строки — это возвраты freezing и hot. Добавление тестов для холодной и жаркой ветки подняло бы это число.

Prompt
Напиши файл теста PHPUnit с функцией describeTemperature, которая возвращает freezing, mild или hot в зависимости от температуры, и один тест, проверяющий только ветку mild. Запусти phpunit с расширением для покрытия и покажи вывод --coverage-text с процентом покрытия строк.
Вывод: PHP-скрипт
Measure the coverage