Улучшение кода не должно сказываться на его первоначальной (после проведенных доработок) функциональности. Как минимум, после переработки приложение не должно содержать больше ошибок на единицу строк кода, чем до начала этого процесса. Достичь этого можно с помощью внедренных в приложение процедур по проверке правильности работы функций программы. Если принять содержимое функции за черный ящик (имеющий определенную вами функциональность), то по реакции функции на набор входных значений можно судить о правильности ее работы. На этом принципе можно построить несложную, но достаточно функциональную схему тестирования кода.
Процедуры тестирования кодаРазберем простейший случай организации процедуры тестирования качества кода на примере введения тестирования работоспособности всего одной функции, выполняющей, например, несложные преобразования текста... Предположим, в вашей программе понадобилась некая функция, которая увеличивает длину строкового представления целого числа до указанной величины с помощью добавления слева символов «0».
Пример функцииВот как выглядит функция, которую впоследствии будет проверять сам класс, в который она будет входить:
<?
function addspace( $int_,$len )
{
$i=0;
$str_=trim($int_);
while (strlen($str_)<$len)
{
$str_="0".$str_;
if ($i++>$len) break;
}
return $str_;
}
?>
Этот код сознательно написан несколько некорректно, чтобы вы могли проследить, как функционируют методы отлова таких ситуаций на практике. Некорректность состоит в неверной обработке отрицательных значений.
Введение тестирующей функцииЕсли на этапе создания новой функции сразу создать код, проверяющий ее работоспособность путем анализа соответствия массивов входных значений с выходными, то при дальнейшей доработке этой функции можно не беспокоиться о ее работоспособности — достаточно запустить этот тестирующий код, и тогда можно будет сделать вывод, что функция работает корректно либо не работает. Далее будет показан несложный пример такого тестирующего кода для нашей функции обработки текста.
Проблемы, возникающие в процессе разработки тестирующих функцийОсновная проблема при построении механизма проверки функций — это осуществление разработки кода для контроля нужной вам функциональности. Наибольшая сложность в организации процесса производства программного продукта при этом состоит в том, чтобы создавать тестирующий код по мере добавления новых функций в ваше приложение.
Результаты тестирования
Хорошим тоном будет создание «самотестирующегося кода» начиная с самого начала разработки класса (функции) на PHP. После внесения некоторых изменений в код функции разработчику достаточно запустить тестирующий код, который выдаст результаты сравнения эталонных данных с текущими. Можно долго спорить про то, как лучше оформлять результаты такого тестирования, но, в том случае если вы еще не успели внедрить никакие методы тестирования в ваш технологический процесс разработки программного обеспечения, будет хорош любой вариант. Для простоты реализации лучше всего подойдет вариант с лог-файлом, в который будут заноситься результаты тестирования функций. При условии расположения ваших программных модулей на платформе *nix можно также смело использовать возможности демона syslogd, встроенного в операционные системы этого класса.
Способы записи отладочной информацииНа самом деле вариант размещения результатов тестирования имеет большее значение для обеспечения безопасности операционной системы, чем для результатов самого тестирования. В случае вывода результатов тестирования непосредственно в пользовательское приложение вы можете раскрыть данные про размещение ваших скриптов на сервере, что недопустимо по соображениям безопасности. С учетом этого самый простой вариант функции логирования ошибок (накопления отладочных сообщений) может выглядеть следующим образом:
<?
class text_process
{
...
function err_log($str)
{
$fp=fopen("./text_process.log","a+");
fwrite($fp,date("Y-m-d H:i:s")." error: ".trim($str)."\n");
fclose($fp);
}
...
}
?>
Внедрение функции тестированияДля того чтобы упростить процесс тестирования, нужные функции можно вынести в класс. Он будет содержать кроме нашей функции еще и некий код для ее тестирования. С учетом приведенных выше рассуждений функция класса, необходимая для организации тестирования, может выглядеть следующим образом:
<?
class text_process
{
...
function test()
{
if ( ($res=$this->addspace(0,3))!=="000" )
$this->err_log("add_space(0,3) ()!==\"000\" is: $res");
if ( ($res=$this->addspace(1,3))!=="001" )
$this->err_log("add_space(1,3) ()!==\"001\" is: $res");
if ( ($res=$this->addspace(500,1))!=="500" )
$this->err_log("add_space(500,1) ()!==\"500\" is: $res");
}
...
}
?>
Автоматический вызов процедуры тестирования
Разумеется, самого создания тестирующего кода еще недостаточно для организации процедуры контроля за качеством функций. Необходимо организовать постоянный запуск этих процедур. В случае с веб-скриптами одним из лучших способов вызова функций тестирования будет запуск такого кода из конструктора класса. При этом разработчику придется подумать о способах уменьшения «накладных расходов», которые неизбежны при таком вызове конструктора. Для этого следует сократить количество запусков тестирований кода, например путем выполнения периодического тестирования. При этом вполне адекватной мерой ограничения дополнительных затрат на вызов тестирующего кода может быть создание локальной переменной класса, управляющей запуском нужных процедур. Смысл состоит в том, что выполнять необходимые процедуры следует только при установке определенного значения этой переменной. Вот как может выглядеть конструктор класса, содержащий запуск тестирования в самом конструкторе:
<?
class text_process
{
...
var $testing;
function text_process($test=FALSE)
{
if ($test===TRUE)
$this->test();
}
...
}
?>
Для выполнения регламентного тестирования можно последовательно выполнить создание всех классов вашего проекта с помощью специально созданного сервисного кода. Скрипт, созданный для этих целей, можно будет запускать, например, после выполнения очередной доработки программной системы и окончания отлова синтаксических ошибок.
Негативные последствия внедрения функций тестированияСледует отметить также и тот факт, что введение методов тестирования в структуры ваших программ приведет к некоторому усложнению кода. Кроме того, создание новых возможностей приводит к неизбежному усложнению тестирующих функций.
Приведенный в статье пример тривиален. Реальные приложения будут содержать более сложные функции и наборы входных данных. Но одно несомненно — применение таких методов тестирования поможет вам сделать процесс разработки программного обеспечения более защищенным от ошибок. И это только увеличит уровень доверия к вашим приложениям со стороны пользователей.
В процессе разработки модуля функция изменилась. По результатам тестирования я определил характер ошибок и место их возникновения. Как уже было замечено ранее, функция неверно отрабатывала отрицательные входные параметры. Эта ошибка стала видна еще на стадии проектирования благодаря некоторому изменению в тестирующей функции:
<?
class text_process
{
...
function test($name)
{
...
if ( ($res=$this->addspace(-5,6))!=="-00005" )
$this->err_log("add_space(-5,6) ()!==\"-00005\" is: $res");
}
...
}
?>
Указанный метод тестирования программного обеспечения в нем самом — это чисто стратегический ход, который не даст разработчику сиюминутной выгоды и может затянуть развитие проекта. Но со временем в процессе длительной разработки промышленного варианта (успешно функционирующего достаточное время в целевой среде приложения) вы таким образом можете получить значительную экономию средств на этапах отладки приложения.
Ссылки по теме
- PHP — язык веб-программирования
- Экстремальное программирование «по-русски»
Статья получена: hostinfo.ru