Почему обычные юнит-тесты не спасают, и что такое E2E?
Представьте: вы написали идеальный код. Юнит-тесты зеленые, покрытие 90%, архитектура — конфетка. Вы выкатываете релиз... а пользователи жалуются, что кнопка «Оплатить» не работает, хотя в базе данных все записи корректны. Знакомая боль?
Проблема в том, что юнит-тесты проверяют изолированные куски кода. Они не видят, как ваш PHP-метод взаимодействует с JavaScript-валидатором на фронте, как сессия передается через куки и что происходит, когда Redis внезапно упал. Именно здесь на сцену выходит E2E (End-to-End) тестирование — или, по-русски, сквозное тестирование.
E2E-тесты имитируют поведение реального пользователя: кликают по кнопкам, заполняют формы, проверяют редиректы и API-ответы. В мире PHP это особенно актуально, потому что типичное приложение — это сложный клубок из Laravel/Symfony, базы данных, очередей и внешних сервисов. Без E2E вы рискуете пропустить баги, которые разрушат пользовательский опыт.
Инструменты для E2E тестирования PHP-проектов
В PHP-экосистеме есть два главных игрока. Не буду томить — вот они:
- Codeception — самый популярный фреймворк, который объединяет юнит-, функциональные и E2E-тесты. Из коробки поддерживает Selenium WebDriver, PHPBrowser и REST API.
- PHPUnit + Selenium WebDriver — классический связка, где PHPUnit отвечает за запуск, а Selenium — за эмуляцию браузера. Требует больше ручной настройки, но даёт полный контроль.
Лично я рекомендую Codeception для старта: он дружит с популярными CMS (WordPress, Drupal) и фреймворками (Laravel, Yii2), а конфигурация занимает 10 минут.
Установка Codeception для E2E
Создайте в корне проекта файл composer.json (если его нет) и выполните:
composer require --dev codeception/codeception codeception/module-webdriver codeception/module-phpbrowser
Затем инициализируйте фреймворк:
vendor/bin/codecept init
Вас спросят, какой тип тестов создавать. Выбирайте Acceptance (E2E). После этого появится папка tests/acceptance и конфиг codeception.yml.
Пишем первый E2E-тест: регистрация пользователя
Самый частый сценарий — регистрация. Давайте проверим, что форма работает корректно и после отправки пользователь видит приветствие.
Конфигурация для работы с браузером
Откройте tests/acceptance.suite.yml и настройте модуль WebDriver (для Chrome):
actor: AcceptanceTester
modules:
enabled:
- WebDriver:
url: 'http://localhost:8000' # URL вашего локального сервера
browser: chrome
window_size: 1920x1080
capabilities:
chromeOptions:
args: ["--headless", "--no-sandbox"] # headless для CI
- Db:
dsn: 'mysql:host=localhost;dbname=testdb'
user: 'root'
password: ''
populate: true
cleanup: true
Важно: не забудьте запустить Selenium Server (или ChromeDriver) в отдельном терминале:
java -jar selenium-server-standalone.jar
Код теста
Создайте файл tests/acceptance/RegistrationCest.php:
<?php
use Codeception\Util\Locator;
class RegistrationCest
{
public function _before(AcceptanceTester $I)
{
$I->amOnPage('/register');
}
public function testSuccessfulRegistration(AcceptanceTester $I)
{
// 1. Заполняем форму
$I->fillField('input[name="name"]', 'Иван Петров');
$I->fillField('input[name="email"]', 'ivan@example.com');
$I->fillField('input[name="password"]', 'StrongPass123!');
$I->fillField('input[name="password_confirmation"]', 'StrongPass123!');
// 2. Отправляем
$I->click('button[type="submit"]');
// 3. Ждём редирект и проверяем приветствие
$I->waitForElement('.alert-success', 5);
$I->see('Добро пожаловать, Иван Петров!');
// 4. Проверяем, что пользователь в БД
$I->seeInDatabase('users', ['email' => 'ivan@example.com']);
}
public function testValidationErrors(AcceptanceTester $I)
{
// Пустая форма
$I->click('button[type="submit"]');
$I->see('Поле email обязательно');
$I->see('Пароль должен содержать минимум 8 символов');
}
}
Запускаем тест:
vendor/bin/codecept run acceptance RegistrationCest
Если всё зелёное — вы только что автоматизировали проверку, которая раньше отнимала у QA-инженера 5 минут ручного кликанья.
E2E тестирование API: без браузера, но с реальными данными
Не все сценарии требуют браузера. Часто нужно проверить, что ваш REST API корректно обрабатывает запросы и возвращает правильные HTTP-статусы. Codeception позволяет это делать без запуска Selenium — достаточно модуля PhpBrowser.
Пример: тестирование эндпоинта логина
<?php
class ApiLoginCest
{
public function testLoginWithValidCredentials(ApiTester $I)
{
$I->haveHttpHeader('Content-Type', 'application/json');
$I->sendPost('/api/login', [
'email' => 'admin@site.com',
'password' => 'secret'
]);
$I->seeResponseCodeIs(200);
$I->seeResponseIsJson();
$I->seeResponseContains('"token"');
$I->seeResponseMatchesJsonType([
'token' => 'string'
]);
}
public function testLoginWithInvalidPassword(ApiTester $I)
{
$I->sendPost('/api/login', [
'email' => 'admin@site.com',
'password' => 'wrong'
]);
$I->seeResponseCodeIs(401);
$I->seeResponseContains('Неверный пароль');
}
}
Для этого понадобится отдельный конфиг api.suite.yml с модулем REST:
modules:
enabled:
- REST:
url: 'http://localhost:8000/api'
depends: PhpBrowser
Такие тесты работают в 10 раз быстрее браузерных и идеально подходят для CI/CD пайплайнов.
Типичные ошибки при E2E тестировании PHP
Даже опытные разработчики наступают на эти гра