Проверка работы index.php инструменты и сценарии тестирования

Раздел: Разработка на PHP -> Тестирование веб-страниц

Файл index.php часто является единственной точкой входа для PHP-приложения. От его корректной работы зависит запуск всех компонентов: загрузка конфигурации, инициализация маршрутизатора, обработка запросов. Тестирование этого файла позволяет выявить ошибки на ранних этапах и избежать простоев.

Способы тестирования index.php

Как провести полное функциональное тестирование index.php с помощью PHPUnit и встроенного сервера?

Наиболее надёжный способ - запустить реальный HTTP-сервер, отправить к нему запросы и проверить ответы. Для этого используется встроенный сервер PHP и клиент Guzzle внутри тестового класса.

class IndexPhpTest extends TestCase
{
    private static $serverProcess;
    private static $baseUrl;

    public static function setUpBeforeClass(): void
    {
        $port = rand(8000, 9000);
        self::$baseUrl = "http://127.0.0.1:$port";
        $docRoot = realpath(__DIR__ . '/../public');
        self::$serverProcess = proc_open(
            "php -S 127.0.0.1:$port -t $docRoot",
            [
                0 => ['pipe', 'r'],
                1 => ['pipe', 'w'],
                2 => ['pipe', 'w']
            ],
            $pipes
        );
        sleep(1); // ждём запуск сервера
    }

    public static function tearDownAfterClass(): void
    {
        if (self::$serverProcess) {
            proc_terminate(self::$serverProcess);
        }
    }

    public function testHomePageReturns200(): void
    {
        $client = new \GuzzleHttp\Client(['base_uri' => self::$baseUrl]);
        $response = $client->get('/');
        $this->assertEquals(200, $response->getStatusCode());
        $this->assertStringContainsString('Главная', (string)$response->getBody());
    }
}

Типичные проблемы и их решения

  • Порт занят - используйте случайный порт или проверку занятости.
  • Сервер не запустился - увеличьте задержку sleep() или проверьте вывод ошибок.
  • Зависание процесса - в tearDown используйте proc_terminate и proc_close.

Как протестировать index.php путём его прямого включения?

Метод подходит для простых приложений без сложной инициализации. В тесте устанавливаются суперглобальные переменные, затем подключается index.php. Результат перехватывается через буферизацию.

public function testDirectInclude()
{
    $_SERVER['REQUEST_METHOD'] = 'GET';
    $_SERVER['REQUEST_URI'] = '/test';
    $_GET = ['id' => 1];
    ob_start();
    require __DIR__ . '/../public/index.php';
    $output = ob_get_clean();
    $this->assertStringContainsString('test', $output);
}

Проблемы

  • Отправка заголовков - используйте ob_start до require.
  • Глобальное состояние - сбрасывайте суперглобальные массивы после каждого теста.
  • Автозагрузка - убедитесь, что автозагрузчик подключён до index.php.

Как эмулировать HTTP-запросы с помощью Symfony BrowserKit?

Если приложение использует Symfony компоненты, можно применить BrowserKit для имитации запросов. Этот метод не требует запуска сервера.

use Symfony\Component\BrowserKit\HttpBrowser;
use Symfony\Component\HttpClient\HttpClient;

$browser = new HttpBrowser(HttpClient::create());
$crawler = $browser->request('GET', 'http://localhost/index.php/?page=about');
$this->assertCount(1, $crawler->filter('h1:contains("О нас")'));

Проблемы

  • Зависимости - требуется установка symfony/browser-kit и symfony/http-client.
  • Ограничения - не поддерживает сессии “из коробки” без дополнительной настройки.

Как проверить производительность index.php с помощью Apache Bench?

Инструмент ab (Apache Bench) позволяет выполнить нагрузочное тестирование и оценить количество запросов в секунду.

ab -n 100 -c 10 http://localhost/index.php

Результат покажет среднее время ответа, количество успешных запросов и пропускную способность.

Проблемы

  • Требуется установленный сервер - без запущенного веб-сервера тест не выполнить.
  • Не тестируется логика - ab проверяет только HTTP-статус, а не содержимое ответа.

Как найти уязвимости index.php в тестах безопасности?

Автоматическая отправка вредоносных данных (SQL-инъекции, XSS) помогает выявить слабые места обработки входных параметров.

$payload = "' OR 1=1 -- ";
$response = $client->get('/search?q=' . urlencode($payload));
$this->assertStringNotContainsString('Ошибка SQL', (string)$response->getBody());

Проблемы

  • Ложные срабатывания - требуется ручная проверка каждого случая.
  • Сложность автоматизации - необходимо писать специфичные тесты под каждую уязвимость.

Расширенные примеры тестирования index.php

Ниже приведены подробные сценарии с полными реализациями на PHPUnit.

Пример
// Пример 1: Полный тест с встроенным сервером и проверкой POST-запроса
class IndexPhpAdvancedTest extends TestCase
{
    private static $process;
    private static $baseUrl;

    public static function setUpBeforeClass(): void
    {
        $port = getenv('TEST_PORT') ?: 8081;
        self::$baseUrl = "http://127.0.0.1:$port";
        $dir = __DIR__ . '/../public';
        self::$process = proc_open(
            "php -S 127.0.0.1:$port -t $dir",
            [0 => STDIN, 1 => STDOUT, 2 => STDERR],
            $pipes
        );
        usleep(500000); // 0.5 сек
    }

    public static function tearDownAfterClass(): void
    {
        if (self::$process) {
            proc_terminate(self::$process);
        }
    }

    public function testPostFormRedirects(): void
    {
        $client = new \GuzzleHttp\Client(['base_uri' => self::$baseUrl]);
        $response = $client->post('/submit', [
            'form_params' => ['name' => 'Тест', 'email' => 'test@example.com']
        ]);
        $this->assertEquals(302, $response->getStatusCode());
        $this->assertEquals('/success', $response->getHeaderLine('Location'));
    }

    public function test404Page(): void
    {
        $client = new \GuzzleHttp\Client(['base_uri' => self::$baseUrl, 'http_errors' => false]);
        $response = $client->get('/nonexistent');
        $this->assertEquals(404, $response->getStatusCode());
        $this->assertStringContainsString('Страница не найдена', (string)$response->getBody());
    }

    public function test500OnInternalError(): void
    {
        // Предполагается, что приложение выбрасывает исключение на определённом маршруте
        $client = new \GuzzleHttp\Client(['base_uri' => self::$baseUrl, 'http_errors' => false]);
        $response = $client->get('/trigger-error');
        $this->assertEquals(500, $response->getStatusCode());
    }
}
PHPUnit 9.5.10 by Sebastian Bergmann.

...                                                                 3 / 3 (100%)

Time: 0.98 seconds, Memory: 6.00 MB

OK (3 tests, 5 assertions)
Пример
// Пример 2: Тестирование с помощью mock-объектов для базы данных
// Допустим, index.php использует класс Database, соединение которого нужно имитировать

use PHPUnit\Framework\TestCase;

class IndexWithMockTest extends TestCase
{
    public function testDatabaseQueryMocked(): void
    {
        // Создаём заглушку для PDO
        $mockPDO = $this->createMock(PDO::class);
        $mockStmt = $this->createMock(PDOStatement::class);
        $mockStmt->method('fetchAll')->willReturn([['id' => 1, 'title' => 'Мок']]);
        $mockPDO->method('query')->willReturn($mockStmt);

        // Подставляем заглушку в контейнер зависимостей (если используется)
        // App::setDatabase($mockPDO);

        // Выполняем index.php с определённым маршрутом
        $_SERVER['REQUEST_URI'] = '/list';
        $_SERVER['REQUEST_METHOD'] = 'GET';
        ob_start();
        require __DIR__ . '/../public/index.php';
        $output = ob_get_clean();

        $this->assertStringContainsString('Мок', $output);
    }
}
PHPUnit 9.5.10
.
Time: 0.05 seconds
OK (1 test, 2 assertions)
Пример
// Пример 3: Тестирование разных HTTP-методов (PUT, DELETE)
public function testPutMethodUpdatesResource(): void
{
    $client = new \GuzzleHttp\Client(['base_uri' => self::$baseUrl]);
    $response = $client->put('/resource/5', [
        'json' => ['value' => 'обновлено']
    ]);
    $this->assertEquals(200, $response->getStatusCode());
    $body = json_decode((string)$response->getBody(), true);
    $this->assertEquals('обновлено', $body['value']);
}

public function testDeleteMethodRemovesResource(): void
{
    $client = new \GuzzleHttp\Client(['base_uri' => self::$baseUrl]);
    $response = $client->delete('/resource/5');
    $this->assertEquals(204, $response->getStatusCode());
}
PHPUnit 9.5.10
..
Time: 0.15 seconds
OK (2 tests, 2 assertions)

Тестирование index.php - comments

En
Test index php (php)