Тестирование
Тест — код, который сам открывает страницу приложения и проверяет ответ: код состояния, сработавший маршрут, текст в HTML. Запустив тесты после изменения, вы сразу видите, не сломалось ли что-то в другом месте. Laminas использует для этого PHPUnit и пакет laminas-test.
Установка
composer require --dev laminas/laminas-testКлюч --dev означает, что пакет нужен только при разработке. В заготовке уже есть файл настроек phpunit.xml.dist и пример теста в module/Application/test.
Где лежат тесты
Тесты модуля кладут в module/<Модуль>/test. Сообщите об этой папке в двух местах. В composer.json — раздел autoload-dev:
{
"autoload-dev": {
"psr-4": {
"ApplicationTest\\": "module/Application/test/",
"BlogTest\\": "module/Blog/test/"
}
}
}В phpunit.xml.dist — ещё одна папка в наборе тестов:
<testsuites>
<testsuite name="Application Test Suite">
<directory>./module/Application/test</directory>
<directory>./module/Blog/test</directory>
</testsuite>
</testsuites>После этого выполните composer dump-autoload.
Первый тест
Создайте файл вручную:
// module/Blog/test/Controller/PostControllerTest.php
namespace BlogTest\Controller;
use Blog\Controller\PostController;
use Laminas\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;
class PostControllerTest extends AbstractHttpControllerTestCase
{
protected function setUp(): void
{
$this->setApplicationConfig(
include __DIR__ . '/../../../../config/application.config.php'
);
parent::setUp();
}
public function testLoginPageOpens(): void
{
$this->dispatch('/login', 'GET');
$this->assertResponseStatusCode(200);
$this->assertControllerName(AuthController::class);
$this->assertMatchedRouteName('login');
}
}Метод setUp() выполняется перед каждым тестом и загружает настройки приложения. dispatch() отправляет запрос внутри PHP, без веб-сервера, а методы assert... проверяют результат.
Запуск
vendor/bin/phpunitPHPUnit напечатает точку за каждый пройденный тест и строку OK в конце. Если страница вернёт другой код, появится сообщение о том, какой тест не прошёл и что ожидалось.
Подмена сервисов
Тесту не нужна настоящая база. Сервис в контейнере заменяют заглушкой — объектом, который возвращает заранее заданные данные:
use Blog\Model\Post;
use Blog\Model\PostTable;
public function testViewShowsPost(): void
{
$post = new Post();
$post->exchangeArray(['id' => 1, 'title' => 'Первая статья', 'body' => 'Текст']);
$table = $this->createMock(PostTable::class);
$table->method('find')->willReturn($post);
$services = $this->getApplicationServiceLocator();
$services->setAllowOverride(true);
$services->setService(PostTable::class, $table);
$this->dispatch('/blog/1');
$this->assertResponseStatusCode(200);
$this->assertStringContainsString('Первая статья', $this->getResponse()->getContent());
}setAllowOverride(true) разрешает заменить уже описанный сервис. Контроллер получит заглушку вместо PostTable, и запрос к базе не выполнится.
Частые проверки
| Метод | Что проверяет |
|---|---|
assertResponseStatusCode(200) | Код ответа |
assertMatchedRouteName('blog') | Сработавший маршрут |
assertControllerName($class) | Контроллер из маршрута |
assertActionName('index') | Действие |
assertRedirectTo('/blog') | Перенаправление на адрес |
Отправку формы проверяют третьим аргументом dispatch(): $this->dispatch('/blog/add', 'POST', ['title' => 'Тест']).
Частая ошибка
Тесты, работающие с настоящей базой разработчика, портят данные и проходят по-разному на разных компьютерах. Подменяйте классы таблиц заглушками, как в примере выше, или заведите отдельную тестовую базу и укажите её в настройках, которые загружаются только в тестах.