Поддержание качества web-приложения, написанного на языке php

ПОДДЕРЖАНИЕ КАЧЕСТВА WEB-ПРИЛОЖЕНИЯ, НАПИСАННОГО НА ЯЗЫКЕ PHP Д.Г. Юдин

Научный руководитель - к. т.н., доцент Б.А. Крылов

В статье рассматриваются методы повышения и поддержания на должном уровне качества web-приложения. Так же приведено сравнение различных сред для создания тестов. Статья будет полезна тем, кто только собирается вводить тестирование своих приложений и не знает, с чего начать.

Введение

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

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

При поддержке какого-либо продукта главная задача - минимизировать затраты на выполнение работ. Имеется в виду время, потраченное на введение изменения. Для этого работа должна быть сделана «с первого раза». В статье рассмотрены некоторые приемы и методики снижения количества ошибок и уменьшения времени на их обнаружение, а также способы поддержания качества web-приложения.

Приемы, способствующие уменьшению ошибок при написании кода [1]

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

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

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

if( $param = 10 ) {

}

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

if( 10 == $param ) {

}

Тогда при опечатке парсер выдаст сообщение об ошибке, так как константе нельзя присвоить значение. Впрочем, как упоминалось ранее, такая конструкция вызывает много споров. Ведь она несколько нелогична, все же мы проверяем значение $param. Масла в огонь также подливают высказывания, что в «нормальных» языках присваивание внутри условия недопустимо.

Сопровождение приложения

Как сказано выше, обычно заключается договор на поддержку web-приложения. Как правило, этот договор срабатывает при каких-либо непредвиденных обстоятельствах вроде атаки на сайт. Поэтому лучше быть готовым до того, как произойдет что-нибудь плохое. Для этого хорошей практикой будет постоянное отслеживание работы приложения в критических местах и отправка уведомлений, если случилось нечто, выходящее за рамки ожиданий. Например, следует отслеживать ошибки выполнения запросов к базе данных и/или значения переданных в функцию параметров. Также полезно проверять вывод в браузер. Например, в ExpertCMS для имен переменных в шаблонизаторе используется конструкция {имя переменной}. Наличие такой строки в выводе может означать, что какой-то из модулей отработал неправильно либо вообще не отработал.

В языке PHP есть встроенный механизм для добавления проверок в код. Это так называемые assert-проверки. Суть их состоит в том, что в код программы добавляются проверочные конструкции, которые можно централизовано включать/выключать. С помощью них удобно проверять, например, параметры, переданные в функцию. Кроме того, можно определить обработчик ошибок, в котором написать, что с этой ошибкой сделать. Например, в течение гарантийного периода полезно оставить включенными assert-проверки, а в обработчике ошибок сделать отправку сообщений об ошибках программисту на почту. В таком случае не придется допрашивать клиента, что он сделал, чтобы ошибка возникла. К тому же, можно исправить ошибку до того, как ее последствия зашли слишком далеко. Например, злоумышленник, взламывающий сайт через sql-injection, скорее всего своими попытками сгенерирует ошибку в запросе к базе данных.

Приемочное тестирование

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

Для web-приложений тестирование интерфейса можно осуществлять с помощью пакета программ Selenium. Данный инструмент появился относительно недавно. Первая

демо-версия вышла в 2005 г., однако активно использовать его стали только в 2007 г. Этот комплекс программ состоит из Selenium-Core, Selenium-RC и SeleniumlDE.

<table> <tr>

<td>open</td>

<td>/change_address_form.html</td> <td></td> </tr> <tr>

<td>type</td> <td>address_field</td> <td>Betelgeuse state prison</td> </tr> <tr>

<td>clickAndWait</td> <td>//input[@name='Submit']</td> <td></td> </tr> <tr>

<td>verifyTextPresent</td> <td>Address change successful</td> <td></td> </tr> </table>

Как видно, формат теста довольно прост. Это таблица, в которой строки -последовательность команд, а столбцы - имя и параметры команды. Такие тесты можно собирать в наборы и запускать все или по отдельности. В дальнейшем эти тесты можно использовать для регрессионного тестирования при внесении изменений.

Такие тесты должны писаться на основе userstory и обязательно не тем человеком, который писал приложение.

Модульное тестирование

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

• Поощрение изменений. Модульное тестирование позже позволяет программистам проводить рефакторинг, будучи уверенными, что модуль по-прежнему работает корректно (регрессионное тестирование). Это поощряет программистов к изменениям кода, поскольку достаточно легко проверить, что код работает и после изменений.

• Упрощение интеграции. Модульное тестирование помогает устранить сомнения по поводу отдельных модулей и может быть использовано для подхода к тестированию «снизу вверх» - сначала тестируются отдельные части программы, затем программа в целом.

• Документирование кода. Модульные тесты можно рассматривать как «живой документ» для тестируемого класса. Клиенты, которые не знают, как использовать данный класс, могут использовать модульный тест в качестве примера.

Фреймворки

На сегодняшний день все фреймворки для модульного тестирования являются PHP-клонами фреймворка JUnit. Самые используемые - это PHPUnit и SimpleTest. Оба этих фреймворка реализуют простую концепцию. Есть класс - набор тестов. Все методы этого класса, название которых начинается с ключевого слова test, являются отдельными тестами. В тестах пишутся утверждения. Если утверждение оказывается ложным, то, значит, тест не успешен. Как сказано выше, эти наборы инструментов идентичны по идеологии, однако, они различаются по полноте реализации различных аспектов тестирования. Для удобства выбора между ними составлена таблица [2, 3].

Описание PhpUnit SimpleTest

Суперкласс для тестового набора и предположения + +

Результаты в HTML + +

Автоматическая загрузка тестовых наборов - +

mock-объекты + +

Набор тестов для веб + +

Частичные тоск'и +

Поддержка cookie + +

Поддержка редиректов + +

Парсинг форм + +

Запуск из командной строки + +

Вывод в XML + +

HTTP авторизация + +

Поддержка SSL + +

Поддержка прокси + +

Поддержка фреймов +

Поддержка тестирования загрузки файлов + +

Тестирование исключений + +

Поддержка тега base + +

Покрытие кода + -

Взаимодействие с Selenium-RC + -

Тестирование производительности + -

Незаконченные тесты + -

Таблица. Сводные характеристики фреймворков для модульного тестирования

Как видно из таблицы, написание приемочных тестов для Selenium-RC доступно только в PHPUnit. Однако PHPUnit поставляется в виде PEAR модуля, поэтому установить его не на свой сервер невозомжно. SimpleTest же целиком написан на PHP, и его можно самостоятельно поставить на хостинг. В версии SimpleTest для разработчиков тоже есть некоторая поддержка Selenium. Для примера напишем какой-нибудь тест.

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

<?php

define('SIMPLE_TEST', '../simpletest/');

require_once(SIMPLE_TEST . 'web_tester.php');

require_once(SIMPLE_TEST . 'reporter.php');

class PaymentTest extends WebTestCase {

function testValidCheck() {

$answer_params = array( '{code}' => '0',

'{message}' => 'Абонент существует, возможен прием платежей' );

$this->get( $this->path . '?action=check&number=5011&type=0' );

$this->assertSource( $this->getAnswer(

$answer_params ) ); }

}

$paytest = new PaymentTest();

$paytest->run( new HtmlReporter( 'windows-1251' ) );

?>

Для примера мы взяли один тестирующий метод. Он тестирует успешную проверку возможности зачисления платежа и состоит из двух вызовов: отправка запроса к шлюзу и сравнение результата с эталоном. В случае несовпадения тест выдаст ошибку.

Непрерывная интеграция

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

К сожалению, готовых решений для PHP найти не удалось.

Заключение

В статье рассматривались способы поддержания качества web-приложений, написанных на языке PHP. В настоящее время разработка ответственных проектов на PHP - уже не редкость. Таким образом, область применения предъявляет свои

требования к надежности таких систем. Для PHP имеется ряд средств, позволяющих поддерживать качество web-приложений, написанных на этом языке. Они включают в себя модульные тесты, web-тесты, тесты интерфейсов.

Литература

1. Кириллов А.В. Пишем PHP код, устойчивый к ошибкам. - Режим доступа: http://www.compdoc.ru/internet/php/code/, своб.

2. Overview of SimpleTest. - Режим доступа: http://simpletest.sourceforge.net/en/overview.html, своб.

3. Bergmann S. PHPUnit Manual. - Режим доступа: http://www.phpunit.de/pocket_guide/3.2/en/index.html, своб.