Разбор методов тестирования главного файла index.php в веб-разработке

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

Основные подходы к тестированию файла index.php

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

Как организовать автоматическую проверку index.php с помощью встроенного сервера и cURL?

Основной способ подходит для регулярного тестирования без ручного открытия браузера. Скрипт test_index.php запускает встроенный сервер PHP, отправляет запрос и сверяет ответ с ожиданиями.


<?php
$port = 8080;
$host = '127.0.0.1';
$docRoot = __DIR__;
$cmd = 'php -S ' . $host . ':' . $port . ' -t ' . escapeshellarg($docRoot) . ' > /dev/null 2>&1 & echo $!';
exec($cmd, $output);
$pid = (int) $output[0];
usleep(300000);
$ch = curl_init('http://' . $host . ':' . $port . '/index.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
exec('kill ' . $pid);
if ($httpCode !== 200) {
    exit('Ошибка: HTTP-статус ' . $httpCode);
}
if (strpos($response, 'Работает') === false) {
    exit('Ошибка: нужная строка не найдена');
}
echo 'Тест успешно завершен';

Test ru index php (тестирование index.php)

Тест успешно завершен

Пошаговое пояснение:

  1. Команда exec запускает сервер в фоновом режиме и записывает идентификатор процесса в переменную $pid.
  2. Пауза usleep даёт серверу время для старта.
  3. Функция curl_init создаёт запрос к файлу index.php.
  4. Опция CURLOPT_HEADER добавляет HTTP-заголовки к телу ответа, чтобы проверить не только содержимое, но и статус.
  5. После запроса процесс сервера завершается командой kill.
  6. Сравнение статуса и тела ответа выявляет отклонения.

Частая проблема: порт уже используется. В такой ситуации сервер не стартует, и $pid содержит идентификатор чужого процесса. Перед запуском следует освободить порт или указать другой параметр. Ещё одна сложность: на Windows команда kill заменяется на taskkill /F /PID.

Как проверить HTTP-заголовки и код ответа вручную?

Для быстрой диагностики достаточно запустить встроенный сервер и выполнить запрос curl с ключом -I.

php -S 127.0.0.1:8000 -t /путь/к/index.php

В другом терминале:

curl -I http://127.0.0.1:8000/index.php
HTTP/1.1 200 OK
Host: 127.0.0.1:8000
Date: ...
Content-Type: text/html; charset=UTF-8

Цель: проверить заголовки, не дожидаясь загрузки всего содержимого. Используется при предварительном тестировании разметки и редиректов.

Ошибка: если файл index.php вызывает функцию header после вывода текста, сервер отправляет предупреждение и заголовок не изменяется. Способ решения: перенести все вызовы header в начало скрипта.

Как проверить синтаксис файла index.php без запуска веб-сервера?

Ошибка в коде часто обнаруживается только после открытия страницы. Встроенная команда php -l выполняет синтаксический анализ без исполнения.

php -l index.php
No syntax errors detected in index.php

Такой способ применяется в конвейерах непрерывной интеграции перед запуском функциональных тестов. Если в файле есть пропущенная точка с запятой или неверная скобка, результат команды отклоняется от ожидаемого.

Проблема: php -l не выполняет код, поэтому не замечает ошибки времени выполнения, такие как обращение к несуществующей функции. Для их обнаружения нужны другие виды тестов.

Как протестировать POST-запрос к index.php?

Если скрипт обрабатывает формы, то без проверки POST-данных не обойтись. Скрипт с файловым дескриптором stream_context_create отправляет запрос и читает ответ.


<?php
$postData = http_build_query(['name' => 'Тестовый пользователь']);
$context = stream_context_create([
    'http' => [
        'method' => 'POST',
        'header' => 'Content-Type: application/x-www-form-urlencoded',
        'content' => $postData,
    ],
]);
$result = file_get_contents('http://127.0.0.1:8000/index.php', false, $context);
if ($result === false) { echo 'Запрос не выполнен'; } else { echo $result; }

Цель: проверить обработку данных формы и ответ скрипта. Такой подход подойдёт для окружения, где нет cURL.

Распространённая ошибка: директива allow_url_fopen отключена в php.ini. Тогда file_get_contents возвращает false и появляется предупреждение. Проверку нужно выполнять с включённой настройкой или через cURL.

Как включить PHPUnit в процесс тестирования index.php?

PHPUnit предоставляет структуру для написания повторяющихся проверок. Тест класса IndexPageTest запускает встроенный сервер в setUp и останавливает его в tearDown.


<?php
class IndexPageTest extends PHPUnit\Framework\TestCase
{
    protected static $pid;
    public static function setUpBeforeClass(): void
    {
        $cmd = 'php -S 127.0.0.1:8081 -t ' . escapeshellarg(__DIR__) . ' > /dev/null 2>&1 & echo $!';
        exec($cmd, $output);
        self::$pid = (int)$output[0];
        usleep(300000);
    }
    public static function tearDownAfterClass(): void
    {
        exec('kill ' . self::$pid);
    }
    public function testHomePageContainsExpectedText(): void
    {
        $content = file_get_contents('http://127.0.0.1:8081/index.php');
        $this->assertStringContainsString('Работает', $content);
    }
    public function testHomePageReturnsOkStatus(): void
    {
        $headers = get_headers('http://127.0.0.1:8081/index.php');
        $this->assertStringContainsString('200', $headers[0]);
    }
}

Цель: интеграция в CI-систему. Каждый тестовый метод изолирован и может проверять отдельную часть ответа.

Типичная ошибка: сервер не останавливается после выполнения тестов. Это приводит к конфликту порта при следующем запуске. Необходимо предусмотреть остановку процесса в tearDownAfterClass.

Как выполнить тестирование маршрутизации в index.php?

Когда index.php обрабатывает разные пути через параметр запроса, полезно использовать router-скрипт. Встроенный сервер PHP поддерживает флаг -S с указанием файла маршрутизации.

php -S 127.0.0.1:8082 router.php

router.php выглядит так:


<?php
if (file_exists(__DIR__ . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH))) {
    return false;
}
$_SERVER['SCRIPT_NAME'] = '/index.php';
require 'index.php';

Цель: имитация веб-сервера с поддержкой чистых URL. Используется при разработке REST API или страниц с многоуровневой маршрутизацией.

Ошибка: если файл index.php использует переменную $_GET['route'], то в router.php надо сохранить исходный REQUEST_URI. Иначе маршрут потеряется. Способ: принудительно присвоить значение функцией parse_url, например $_GET['route'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

Расширенная подборка примеров для тестирования index.php

Дополнительные сценарии помогают охватить ситуации, которые не видны при простой проверке. Каждый пример сопровождается кодом и результатом его работы.

Как проверить несколько сценариев работы index.php за один запуск?

Скрипт запускает сервер один раз, а затем выполняет массив запросов с ожидаемыми статусами и фрагментами ответа.

Пример

<?php
$host = '127.0.0.1';
$port = 8070;
$docRoot = __DIR__;
exec('php -S ' . $host . ':' . $port . ' -t ' . escapeshellarg($docRoot) . ' > /dev/null 2>&1 & echo $!', $out);
$pid = (int)$out[0];
usleep(500000);
$tests = [
    ['url' => '/index.php?page=home', 'status' => 200, 'needle' => 'Домашняя'],
    ['url' => '/index.php?page=about', 'status' => 200, 'needle' => 'О проекте'],
    ['url' => '/missing.php', 'status' => 404, 'needle' => 'Не найдено'],
];
foreach ($tests as $test) {
    $ch = curl_init($host . ':' . $port . $test['url']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $body = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);
    if ($status !== $test['status'] || strpos($body, $test['needle']) === false) {
        echo 'Провал: ' . $test['url'] . PHP_EOL;
        exit(1);
    }
    echo 'Успех: ' . $test['url'] . PHP_EOL;
}
exec('kill ' . $pid);
Успех: /index.php?page=home
Успех: /index.php?page=about
Успех: /missing.php

Такой набор удобен для регрессионного тестирования. При добавлении новой страницы достаточно дописать элемент массива.

Важная деталь: если index.php использует относительные пути, рабочая директория может отличаться. Тогда тест не найдёт файлы подключения. Способ: задать chdir(__DIR__) в начале скрипта.

Как проверить JSON-ответ и заголовок Content-Type?

Для страниц, которые возвращают данные в формате JSON, требуется проверка и структуры, и заголовка.

Пример

<?php
$ch = curl_init('http://127.0.0.1:8071/index.php?format=json');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Accept: application/json']);
$response = curl_exec($ch);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
$decoded = json_decode($response, true);
if (stripos($contentType, 'application/json') === false) {
    exit('Неправильный Content-Type');
}
if (!isset($decoded['status'])) {
    exit('JSON не содержит поле status');
}
echo 'JSON-ответ корректен';
JSON-ответ корректен

Такой подход применяется при тестировании AJAX-обработчиков и API-методов, размещённых в index.php.

Ошибка: index.php отправляет HTML с предупреждением PHP перед JSON. Тогда json_decode возвращает null. Нужно проверить ошибки в логах и отключить вывод предупреждений.

Как отправить HTTP-запрос без cURL и file_get_contents?

Если нет ни cURL, ни включённого allow_url_fopen, используется сокет. Через stream_socket_client отправляется текстовое HTTP-сообщение.

Пример

<?php
$socket = stream_socket_client('tcp://127.0.0.1:8072', $errno, $errstr, 5);
if (!$socket) {
    exit($errstr);
}
$request = "GET /index.php HTTP/1.1\r\n";
$request .= "Host: 127.0.0.1\r\n";
$request .= "Connection: close\r\n\r\n";
fwrite($socket, $request);
$response = '';
while (!feof($socket)) {
    $response .= fgets($socket);
}
fclose($socket);
$parts = explode("\r\n\r\n", $response, 2);
$headers = $parts[0];
$body = isset($parts[1]) ? $parts[1] : '';
if (strpos($headers, '200 OK') === false) {
    exit('Статус не 200');
}
if (strpos($body, 'Работает') === false) {
    exit('Контент не совпадает');
}
echo 'Сокет-тест пройден';
Сокет-тест пройден

Этот метод даёт полный контроль над передаваемыми данными и подходит для отладки HTTP-протокола на низком уровне.

Сложность: если сервер использует постоянные соединения, без заголовка Connection: close ответ может не завершиться. Цикл while в этом случае выполняется вечно.

Как проверить работу сессии и куки в index.php?

Куки проверяются через CURLOPT_COOKIEJAR и CURLOPT_COOKIEFILE. Это позволяет сохранять идентификатор сессии между запросами.

Пример

<?php
$jarFile = tempnam(sys_get_temp_dir(), 'cookie');
$ch = curl_init('http://127.0.0.1:8073/index.php?session=start');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, $jarFile);
$first = curl_exec($ch);
curl_close($ch);
$ch = curl_init('http://127.0.0.1:8073/index.php?session=check');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, $jarFile);
$second = curl_exec($ch);
curl_close($ch);
unlink($jarFile);
if (strpos($first, 'SID') === false || strpos($second, 'OK') === false) {
    exit('Сессия не работает');
}
echo 'Сессия и куки исправны';
Сессия и куки исправны

Случай использования: проверка авторизации, корзины или форм с защитой от CSRF.

Типичная ошибка: если не указать CURLOPT_COOKIEJAR, второй запрос не получит куки, и сессия не восстановится. Нужно обязательно передать один и тот же файл.

Как проверить поведение index.php при одновременных запросах?

Конкурентные запросы выявляют состояния гонки и проблемы с блокировками. curl_multi позволяет отправить несколько запросов параллельно.

Пример

<?php
$requests = [];
$mh = curl_multi_init();
for ($i = 0; $i < 5; $i++) {
    $ch = curl_init('http://127.0.0.1:8074/index.php?q=' . $i);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_multi_add_handle($mh, $ch);
    $requests[] = $ch;
}
$running = null;
do {
    curl_multi_exec($mh, $running);
} while ($running > 0);
foreach ($requests as $ch) {
    $content = curl_multi_getcontent($ch);
    if (strpos($content, 'ОК') === false) {
        echo 'Ошибка в одном из ответов';
        exit(1);
    }
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}
curl_multi_close($mh);
echo 'Все параллельные запросы завершились успешно';
Все параллельные запросы завершились успешно

Этот пример используется при нагрузочном тестировании одиночного файла index.php и проверке отсутствия взаимных блокировок.

Опасность: при работе с общей файловой сессией одновременные запросы могут портить данные. Тест показывает необходимость использовать блокировки или отдельные механизмы хранения.

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

En
Test ru index php (php)