Практика на Хекслете проверяется автоматическими тестами, к которым вы уже немного привыкли, если смогли добраться до текущего урока. Для тестирования PHP-кода мы используем фреймворк PHPUnit, который, хоть и не единственный, но до сих пор — самый популярный. Имея некоторое представление об ООП, мы можем поговорить о его устройстве.
<?php
namespace App\Tests;
use PHPUnit\Framework\TestCase;
use function App\Math\average;
// Единственная незнакомая синтаксическая конструкция в этом тесте — `extends TestCase`.
// С её помощью реализуется наследование. О наследовании пойдёт разговор в следующих курсах,
// а сейчас достаточно знать, что все методы, которые мы вызываем внутри нашего теста,
// определены в классе `TestCase`, и именно наследование позволяет их использовать.
class MathTest extends TestCase
{
public function testAverage()
{
$this->assertEquals(0, average(0));
$this->assertEquals(5, average(0, 10));
}
}
Не имеет значения предмет тестирования; любой тест PHPUnit всегда описывается в классе с именем Что-тоTest
внутри директории tests
. Если тестируется какой-то конкретный класс с именем Foo
, то по соглашению его тесты располагаются в классе FooTest
. Точно такое же правило с пространством имён без классов. Как правило, структура директорий внутри tests
совпадает со структурой исходных файлов — так проще ориентироваться, и некоторые редакторы позволяют автоматически переключаться между тестом и исходным файлом при такой структуре и именовании.
src/ tests/
`-- Money/Currency.php `-- Money/CurrencyTest.php
`-- IntlFormatter.php `-- IntlFormatterTest.php
`-- Money.php `-- MoneyTest.php
Каждый тестовый класс состоит из тестовых методов. Тестовые методы всегда начинаются с префикса test
, например, testAverage
— только тогда PHPUnit понимает, что это тестовый метод и выполняет его автоматически при прогоне тестов. Тестовые методы пишутся программистом. Нет никаких правил в том, сколько их должно быть и какова должна быть их структура. Если необходимо написать десять разных тестов на одну функцию, то так и нужно делать.
Главная задача любого тестового метода — выполнить ту проверку, ради которой задумывался соответствующий тест. В примере выше тестируется функция average
, находящая среднее арифметическое всех переданных в эту функцию чисел. Average — чистая функция, а значит, её легко тестировать. Достаточно передать в функцию несколько чисел и проверить возвращаемое значение.
Проверки в PHPUnit выполняются с помощью специальных функций — утверждений. Этих функций довольно много, но среди них есть несколько наиболее используемых. Метод assertEquals
принимает на вход два значения:
- Expected. Ожидаемый результат — то, что должна вернуть функция.
- Actual. Результат, который на самом деле вернула функция.
Порядок важен. На его основе PHPUnit формирует вывод, в котором указывает, что ожидалось, а что пришло на самом деле.
Другое популярное утверждение assertTrue
(и assertFalse
). Оно принимает только один аргумент и отлично подходит для тестирования предикатов.
Анализ дизайна
Дизайн тестов на основе классов теряет свою популярность, а во многих языках уже давно не используется. Современный подход растёт из BDD процесса. Синтаксически такие тесты часто полагаются на функции высшего порядка describe
и it
.
<?php
describe('Example', function () {
$object = new stdClass();
$object->name = 'pho';
context('name', function () use ($object) {
it('is set to pho', function() use ($object) {
expect($object->name)->toBe('pho');
});
});
});
Замечу, что в PHP такой стиль выглядит немного тяжёлым из-за обилия синтаксических конструкций.
Дополнительные материалы
- Официальная документация
- Behat (BDD Framework)
- Codeception (Браузерные тесты)
- Начинаем писать тесты (Правильно)
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.