PHPUnit - это фреймворк для тестирования кода (модульные, интеграционные, системные тесты) на PHP. Документация на русском языке достаточная, но на английском все же полная.
К слову документация исчерпывающая, необходимость что-то искать в интернета отпадает. В данной статье я затрону, моменты которые могут тормозить быстрый старт, и очень кратко расскажу про некоторые необходимости, все остальное можно найти в документации.
Установка через composer проста (но есть и другие варианты установки) - в корне директории с php скриптами необходимо:
bashcomposer require --dev phpunit/phpunit ^latest
Если используется автозагрузка классов (PSR-4), тогда в composer.json
необходимо добавить ключ autoload
для указания корневого пространства имен, откуда будут грузится классы:
json"autoload": { "psr-4": { "MyNamespace\\": "src" } }
А если по ходу дела поменялось пространство имен (после того как проект был инициализован), например с MyNamespace
на My\\Space
, то необходимо изменить его в composer.json
и:
bashcomposer update
Если этого не сделать, используя свой идентичный PSR-4 автозагрузчик, тогда при проведении тестов, обработчик автозагрузки классов будет запускаться и PHPUnit будет ругаться на использование непокрывыемого тестами кода, например так::
bash17) ConverterTest::testItemsToArray This test executed code that is not listed as code to be covered or used: - /src/init.php:10 - /src/init.php:11 - /src/init.php:13 - /src/init.php:6 - /src/init.php:7
Написание тестов подробно расписано в этом разделе документации. Там же (в документации) можно прочитать про фикстуры и про тестовых двойников, которые нужны для имитации некоторых объектов кода, а сама имитация нужна для изоляции тестируемого кода.
Тестирующий код следует распологать в отдельной от основго кода директории, например в tests
. В зависимости от переданных параметров PHPUnit может запускать все файлы в директории или конкретный файл.
Например эта команда запустит все файлы в директории tests/Unit/
(и во вложенных директорях) и перед тестами запустит файл tests/Unit/bootstrap.php
:
bashvendor/bin/phpunit --bootstrap tests/Unit/bootstrap.php tests/Unit/
В каждом файле тестов:
PHPUnit\Framework\TestCase
test
и иметь внутри себя утвержденияПредположим у нас есть класс:
phpclass Receipt { const TYPE_COMING = 0; const TYPE_REFUND = 1; public function __construct() { $this->type = self::COMING; } /** * @throws InvalidArgumentException */ public function setType(int $type): self { if($type != self::COMING && $type != self::REFUND) throw new InvalidArgumentException(); $this->type = $type; return $this; } public function getType(): int { return $this->type; } private $type; }
Это упрощенный пример класса из одного рабочего проекта. Класс Receipt
содержит одно поле type
и 2 метода для установки и получения этого поля. При создании объекта этому полю присваивается дефолтное значение. Метод установки значения setType
может выбрасывать исключения при невалидном значении.
Вопросы на которые должен ответить тест:
setType
будет установлено валидное значение?Теперь напишем тест для этого класса:
phpuse PHPUnit\Framework\TestCase; use Receipt; /** * @uses Receipt */ class ReceiptTest extends TestCase { /** * @covers Receipt::__construct * @covers Receipt::setType * @covers Receipt::getType */ public function testSetGetType() { $receipt = new Receipt(); // проверяем дефолтное значение $this->assertSame(Receipt::TYPE_COMING, $receipt->getType()); // проверка установки валидного значения $this->assertSame($receipt, $receipt->setType(Receipt::TYPE_REFUND)); $this->assertSame(Receipt::TYPE_REFUND, $receipt->getType()); // проверка выброса исключения в случае передачи невалидного значения $this->expectException(InvalidArgumentException::class); $receipt->setType(-1); } }
Про опции командной строки детально написано в документации.
Тесты можно запускать через composer, для этого в composer.json
необходимо объявить команды в scripts
, например так:
json"scripts": { "test-unit": "vendor/bin/phpunit --colors=always --coverage-html coverage-report-html --bootstrap tests/Unit/bootstrap.php tests/Unit/", "test-integration": "vendor/bin/phpunit --colors=always --bootstrap tests/Integration/bootstrap.php tests/Integration/", "test-system": "vendor/bin/phpunit --colors=always --bootstrap tests/System/bootstrap.php tests/System/" }
В этом примере объявлено 3 команды на запуск модульных, интеграционных и системных тестов, при этом для каждого теста свои настройки.
Запускать тесты через composer можно так:
bashcomposer run-script test-unit
PHPUnit использует конфигурационный файл для общих настроек тестов, однако на старте его нет, и если запускать тесты без него то можно получить:
bashWarning: No filter is configured, code coverage will not be processed
Решается это генерацией конфига phpunit.xml
при помощи PHPUnit:
bashphpunit --generate-configuration
Все кроме покрытия просто, а здесь я немного задержался :)
Среда организована, тесты написаны, теперь хочется в красивом виде узнать о покрытии кода тестами.
Для начала необходимо установить xdebug библиотеку для нужной версии php:
bashapt install php7.3-xdebug
В самом простом варианте информацию о покрытии можно увидеть в выводе командной строки после завершения тестов при помощи опции --coverage-text
:
Но есть еще html вариант, где значительно больше информации о покрытии в более наглядном виде. Для генерации надо использовать опцию --coverage-html
с указанием директории вывода отчета (пример выше в composer.json
).