Письмові тести
Написання тестів для Nette Tester унікальне тим, що кожен тест являє собою PHP-скрипт, який може бути запущений окремо. Це має великий потенціал. Написавши тест, ви можете просто запустити його, щоб перевірити, чи працює він правильно. Якщо ні, ви можете легко пройтися по тесту в IDE і пошукати помилку.
Ви навіть можете відкрити тест у браузері. Але найголовніше – запустивши його, ви виконаєте тест. Ви відразу ж дізнаєтеся, пройшов він чи не пройшов.
У вступному розділі ми показали дійсно тривіальний тест на використання масиву PHP. Тепер ми створимо свій власний клас, який ми будемо тестувати, хоча він також буде простим.
Почнемо з типової схеми каталогу бібліотеки або проекту. Важливо відокремити тести від решти коду, наприклад, через розгортання, тому що ми не хочемо завантажувати тести на сервер. Структура може бути такою:
├── src/ # code that we will test
│ ├── Rectangle.php
│ └── ...
├── tests/ # tests
│ ├── bootstrap.php
│ ├── RectangleTest.php
│ └── ...
├── vendor/
└── composer.json
Тепер ми створимо окремі файли. Почнемо з класу, що тестується, який
помістимо у файл src/Rectangle.php
І створимо для нього тест. Ім'я файлу тесту має відповідати масці
*Test.php
або *.phpt
, ми виберемо варіант RectangleTest.php
:
Як бачите, методи твердження, такі як Assert::same()
,
використовуються для твердження того, що фактичне значення збігається
з очікуваним.
Останній крок – створення файлу bootstrap.php
. Він містить
загальний код для всіх тестів. Наприклад, автозавантаження класів,
конфігурація оточення, створення тимчасової директорії, хелпери тощо.
Кожен тест завантажує бутстрап і приділяє увагу лише тестуванню.
Бутстрап може виглядати таким чином:
Цей бутстрап передбачає, що автозавантажувач Composer зможе
завантажити і клас Rectangle.php
. Цього може бути досягнуто,
наприклад, установкою секції autoload у
composer.json
, тощо.
Тепер ми можемо запустити тест із командного рядка, як будь-який інший окремий PHP-скрипт. Перший запуск виявить будь-які синтаксичні помилки, і якщо ви не допустили помилок, ви побачите:
$ php RectangleTest.php
OK
Якщо ми змінимо в тесті твердження на false
Assert::same(123, $rect->getArea());
, відбудеться наступне:
$ php RectangleTest.php Failed: 200.0 should be 123 in RectangleTest.php(5) Assert::same(123, $rect->getArea()); FAILURE
Під час написання тестів корисно відловлювати всі екстремальні ситуації. Наприклад, якщо на вході нуль, від'ємне число, в інших випадках порожній рядок, null тощо. Фактично, це змушує вас думати і вирішувати, як має поводитися код у таких ситуаціях. Потім тести виправляють поведінку.
У нашому випадку від'ємне значення має викликати виняток, який ми перевіряємо за допомогою Assert::exception():
І ми додаємо аналогічний тест для висоти. Нарешті, ми перевіряємо, що
isSquare()
повертає true
, якщо обидва виміри однакові.
Спробуйте написати такі тести як вправу.
Добре організовані тести
Розмір файлу з тестами може збільшитися і швидко стати захаращеним. Тому доцільно групувати окремі тестовані області в окремі функції.
Спочатку ми покажемо простіший, але елегантніший варіант,
використовуючи глобальну функцію test()
. Tester не створює її
автоматично, щоб уникнути колізії, якщо у вашому коді є функція з таким
самим ім'ям. Він створюється тільки методом setupFunctions()
, який ви
викликаєте у файлі bootstrap.php
:
Використовуючи цю функцію, ми можемо красиво розділити тестовий файл на іменовані блоки. Під час виконання функції мітки відображатимуться одна за одною.
Якщо вам потрібно запустити код до або після кожного тесту, передайте
його в setUp()
або tearDown()
:
Второй вариант – объектный. Мы создадим так называемый TestCase, который представляет собой класс, где отдельные единицы представлены методами, имена которых начинаются с test-.
На этот раз мы использовали аннотацию @throw
для проверки на
исключения. Более подробную информацию смотрите в главе TestCase.
Функции-помощники
Nette Tester включает в себя несколько классов и функций, которые могут облегчить вам тестирование, например, помощники для тестирования содержимого HTML-документа, для тестирования функций работы с файлами и так далее.
Их описание вы можете найти на странице Helpers.
Аннотирование и пропуск тестов
На выполнение тестов могут влиять аннотации в комментарии phpDoc в начале файла. Например, он может выглядеть следующим образом:
Аннотации гласят, что тест должен выполняться только с PHP версии
7.2 или выше и при наличии PHP расширений pdo и pdo_pgsql. Эти аннотации
контролируются программой запуска тестов командной
строки, которая, если условия не выполняются, пропускает тест и
помечает его буквой s
– пропущен. Однако они не имеют никакого
эффекта, когда тест выполняется вручную.
Описание аннотаций приведено в разделе Аннотации тестов.
Тест также может быть пропущен на основании собственного условия с
помощью Environment::skip()
. Например, мы пропустим этот тест на Windows:
Структура каталогов
Для немного больших библиотек или проектов мы рекомендуем разделить тестовый каталог на подкаталоги в соответствии с пространством имен тестируемого класса:
└── tests/
├── NamespaceOne/
│ ├── MyClass.getUsers.phpt
│ ├── MyClass.setUsers.phpt
│ └── ...
│
├── NamespaceTwo/
│ ├── MyClass.creating.phpt
│ ├── MyClass.dropping.phpt
│ └── ...
│
├── bootstrap.php
└── ...
Ви зможете запускати тести з одного простору імен тобто підкаталогу:
tester tests/NamespaceOne
Edge Cases
Тест, який не викликає жодного методу твердження, є підозрілим і буде оцінено як помилковий:
Error: This test forgets to execute an assertion.
Якщо тест без виклику тверджень дійсно має вважатися коректним,
викличте, наприклад, Assert::true(true)
.
Також підступним може бути використання exit()
і die()
для
завершення тесту з повідомленням про помилку. Наприклад,
exit('Error in connection')
завершує тест із кодом виходу 0, який сигналізує
про успіх. Використовуйте Assert::fail('Error in connection')
.