Статьи

Запись и воспроизведение для тестирования устаревших приложений PHP

Итак, у вас есть этот большой шарик кода. Вы даже не знаете, как вызвать все эти сценарии, но код находится в производстве и работает просто отлично (пока вам не придется менять даже одну строку). Как определить некоторые тесты характеристик, которые описывают, как скрипты .php работают сейчас? Это важная задача, чтобы избежать поломок , но в большинстве случаев параметры сценариев и их ответ вообще не документированы (или задокументированы неправильно).

Куча файлов .php

Типичное унаследованное приложение не имеет единой точки входа: не существует единого index.php, который собирает все запросы, но много разных файлов, каждый из которых принимает некоторые аргументы. Когда эти файлы связаны во многих местах или вызываются из внешних служб, определение их поведения становится нетривиальным. Если тесты не существуют, мы не знаем, ожидают ли они запросов GET или POST, какие параметры они содержат, и, прежде всего, каков должен быть их ответ в правильных и ошибочных случаях.

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

Наши цели

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

Например, запросы SQL UPDATE являются своего рода побочным эффектом наряду с любым файлом, записанным во время выполнения. Хотя запись запросов и ответов является довольно стандартной в PHP, часть побочных эффектов сильно варьируется в зависимости от приложения.

Входные параметры скрипта .php:

  • $ _GET: каждый параметр передается в строку запроса index.php.
  • $ _POST: каждый параметр, передаваемый в запросе POST, когда это применимо.
  • $ _SERVER: информация о заголовках и об удаленном IP-адресе, который сделал запрос.
  • Заголовки HTTP-запроса, такие как User-Agent или Authentication .

В случае, если вы принимаете PUT-запросы, вы должны записать их содержимое (читать со стандартного ввода).

Вместо этого выходные параметры скрипта:

  • код ответа HTTP и набор заголовков.
  • тело ответа.

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

Как записать

ob_start () включает возможности буферизации вывода в PHP: ответ будет буферизироваться вместо немедленной отправки. Мы можем передать обратный вызов этой функции, которая будет вызываться в конце скрипта для регистрации ответа.

Вот другие примеры глобальной черной магии для записи исполнения скрипта PHP:

  • суперглобальные переменные $ _GET и $ _POST доступны в любой области, наряду с $ _SERVER.
  • headers_list () получает заголовки ответа в Apache, но не код ответа. Вы должны войти в него самостоятельно, если вы установите его.

Кстати, getallheaders () или его эквивалент apache_request_headers () не очень надежны для сбора заголовков запросов, так как они зависят от Apache и полагаются на PHP, устанавливаемый как модуль Apache. В руководстве по PHP предлагается использовать переносимые переменные CGI, такие как $ _SERVER, но вам придется разбирать имена заголовков самостоятельно.

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

Абстракция: объект ленты

Когда-то вы купили пустые кассеты для записи с радио или телевидения. Поэтому, работая над записью, я представил класс Tape.

В начале каждого сценария я создавал новую ленту и велел записать ее.

// the name of the script is a parameter of the log filename which is written
$tape = new Tape(__FILE__);
// the callback for registering the response
ob_start(array($tape, 'record'));

Открытые методы на $ tape были доступны для хранения интересных объектов и других переменных, когда это было необходимо во время сценария. Например, побочный эффект, такой как запрос SQL, должен быть сохранен с помощью $ tape-> export ($ Statement).

Если вы пишете один файл журнала для каждого сценария, и это мой совет, вам понадобится способ соотнести запрос, ответы и другую информацию. Для этого мой класс Tape генерирует уникальную метку для каждого объекта:

$this->label = uniqid('tape');

и каждый раз, когда вы звоните:

$tape->export('varname', $variable);

новая строка журнала будет записана как:

tape01234... varname "content"

с var_export () и file_put_contents () с установленным флагом FILE_APPEND.

Выводы

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