Тестирование в PHP: фреймворки и инструменты
Качество кода — основа успешного веб-проекта. Для PHP-разработчиков тестирование перестало быть опцией и стало обязательным этапом разработки. В этой статье разберём три ключевых инструмента: PHPUnit (стандарт индустрии), Pest (современный минимализм) и Codeception (интеграционное тестирование). Вы узнаете, как писать unit-тесты, работать с mock-объектами и внедрять TDD в PHP-проекты.
1. PHPUnit — фундамент тестирования PHP
PHPUnit — де-факто стандарт для модульного тестирования PHP. Он входит в состав Symfony, Laravel и других популярных фреймворков.
Установка и базовый тест
composer require --dev phpunit/phpunit
Пример простого теста для класса калькулятора:
// src/Calculator.php
class Calculator {
public function add($a, $b) {
return $a + $b;
}
}
// tests/CalculatorTest.php
use PHPUnit\Framework\TestCase;
class CalculatorTest extends TestCase {
public function testAddition() {
$calc = new Calculator();
$this->assertEquals(4, $calc->add(2, 2));
}
}
Работа с mock-объектами
PHPUnit предоставляет встроенный механизм для создания заглушек (mock):
public function testUserRepository() {
$mockRepo = $this->createMock(UserRepository::class);
$mockRepo->method('findById')
->willReturn(new User(1, 'Alice'));
$service = new UserService($mockRepo);
$result = $service->getUser(1);
$this->assertEquals('Alice', $result->getName());
}
2. Pest — элегантный синтаксис для тестов
Pest — это обёртка над PHPUnit, предлагающая более лаконичный и читаемый синтаксис. Идеально подходит для проектов, где важна скорость написания тестов.
Установка и пример
composer require --dev pestphp/pest
Сравните с PHPUnit: тот же тест в Pest выглядит так:
// tests/CalculatorTest.php
it('calculates addition', function () {
$calc = new Calculator();
expect($calc->add(2, 2))->toBe(4);
});
Продвинутые возможности
- Higher Order Tests — цепочки вызовов без вложенности
- Architecture Testing — проверка структуры классов
- Snapshot Testing — сравнение с эталонными данными
3. Codeception — для интеграционного и функционального тестирования
Codeception объединяет unit-, функциональные и приёмочные тесты в одном фреймворке. Поддерживает Selenium, Symfony, Laravel, Yii и даже WordPress.
Структура тестов
codecept generate:cest acceptance LoginCest
Пример функционального теста для Laravel:
// tests/functional/UserCest.php
class UserCest {
public function testLogin(FunctionalTester $I) {
$I->amOnPage('/login');
$I->fillField('email', 'user@example.com');
$I->fillField('password', 'secret');
$I->click('Login');
$I->see('Dashboard');
}
}
4. Дополнительные инструменты
- Mockery — гибкая библиотека для mock-объектов (альтернатива встроенным мокам PHPUnit)
- PHPStan / Psalm — статический анализ, выявляющий ошибки до запуска тестов
- Infection — мутационное тестирование: проверяет качество самих тестов
- PHP CodeSniffer — контроль соответствия PSR-12
5. Практический пример: TDD для API-сервиса
Реализуем простой цикл TDD (Test-Driven Development) для сервиса заказов:
Шаг 1. Пишем тест
// tests/OrderServiceTest.php
public function testCreateOrderCalculatesTotal() {
$orderService = new OrderService();
$items = [
['price' => 100, 'quantity' => 2],
['price' => 50, 'quantity' => 1]
];
$total = $orderService->calculateTotal($items);
$this->assertEquals(250, $total);
}
Шаг 2. Реализуем минимальный код
// src/OrderService.php
class OrderService {
public function calculateTotal(array $items): float {
$total = 0;
foreach ($items as $item