Квест → Как хакнуть форму
Прошли: 77

Иногда в PHP нам нужно написать интеграционные тесты, и иногда для этих интеграционных тестов нужен веб-сервер. Встроенный веб-сервер доступен начиная с PHP 5.4 и для этих целей можно использовать его.
Базовый вариант запуска сервера, изложенный в документации PHP, выглядит так:
php -S <addr>:<port> -t <docroot>
Это можно выполнить с помощью команды exec, но проще использовать компонент Symfony Process для управления сервером из теста. Главное, что нужно сделать, — запустить процесс асинхронно, убедиться, что порт свободен и подождать нескольких микросекунд, чтобы сервер запустился.
Следующим требованием является способ вызова веб-сервера. Это можно сделать с помощью curl, но лучше использовать Guzzle, это будет немного аккуратнее. При использовании Guzzle, нужно подавить http-ошибки помощью [‘http_errors’ => false]. Если код выполняется за прокси это можно обойти, установив параметр прокси в пустую строку.
И всё вместе можно собрать в следующее Silex-приложение:
// web/index.php
require_once __DIR__.'/vendor/autoload.php';
$app = new Silex\Application();
$app->get('/testpage/', function () {
return "LOL";
});
$app->run();
и далее такой интеграционный тест:
use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\Process;
use GuzzleHttp\Client;
class IntegrationTest extends TestCase
{
/** @var Process */
private static $process;
public static function setUpBeforeClass()
{
self::$process = new Process("php -S localhost:8080 -t .");
self::$process->start();
usleep(100000); //wait for server to get going
}
public static function tearDownAfterClass()
{
self::$process->stop();
}
public function test404()
{
$client = new Client(['http_errors' => false]);
$response = $client->request("GET", "http://localhost:8080");
$this->assertEquals(404, $response->getStatusCode());
}
public function test200()
{
$client = new Client(['http_errors' => false]);
$response = $client->request("GET", "http://localhost:8080/testpage/");
$this->assertEquals(200, $response->getStatusCode());
}
}
Который может быть запущен так:
> bin/phpunit IntegrationTest.php --bootstrap=vendor/autoload.php
Код использует методы setUpBeforeClass и tearDownAfterClass для запуска одного веб-сервера на один класс-тест и остановки его когда все тесты в этом классе отработали.
Весь код и зависимости можно найти на GitHub.