WebScript.Ru
C:\   главная  ::   о сайте  ::  каталог скриптов  ::  гнездо  ::  форум  ::   авторам  :: Новостройки ::   ХОСТИНГ  ::

|| разделы::
|| поиск по сайту::

|| реклама::
|| новости почтой::
Рассылки Subscribe.Ru ::



Новости сайта WebScript.Ru
Популярные статьи

Hot 5 Stories

|| рекомендуем::




Написание автоматических тестов и среда phpUnit


Прислал: Гусев Антон [ 23.12.2003 @ 13:36 ]
Раздел:: [ Статьи по PHP ]


Программы, которые не тестировали, НЕ РАБОТАЮТ.
Б. Страуструп

Введение

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

Итак, тестирование - деятельность, направленная на выявление такого рода несоответствий между ожидаемым и действительным. Выявляя несоответствия, некорректное поведение на стадии разработки, разработчик сознательно и планомерно уменьшает вероятность того, что с этим придется столкнуться пользователю. Тестировать программы (в частности php-скрипты) вполне можно и вручную. На примере формы обратной связи, понятно, что протестировать ее очень просто. Запустить браузер, зайти на нужный url, заполнить поля, нажать на "Ок", потом зайти в базу и проверить, появилась ли там соотвeтствующая запись. Прекрасно, но после любого изменения скрипта нельзя быть уверенным в его работоспособности. Можно понадеяться на авось и не проверять, работает ли скрипт после очередной модификации или нет, но помните, что если его не протестируете вы, это сделает заказчик во время сдачи проекта или конечный пользователь во время эксплуатации. В первом случае это грозит вам финансовой нестабильностью, а во втором пострадает ваш имидж. Для того, чтобы не тестировать вручную (это долгий, сложный и требующий особой усидчивости процесс), можно написать программу, тестирующую другие программы, или создать автоматизированные тесты.

В любой современной методологии разработки ПО тестирование является неотъемлемой частью процесса, а значимость его написания не ниже значимости написания кода. Профессиональный разработчик обязан создавать наборы различного вида автоматизированных тестов (подробнее о видах тестов, правилах их именования и т.д. можно прочитать в статье Кирилла Максимова "Организация и именование автоматизированных тестов").

Несмотря на очевидную полезность и акцент методологий на процессе тестирования, личный опыт авторов свидетельствует о следующем разбросе мнений web-программистов насчет автоматизированного тестирования собственных скриптов:

  • "Никто не пишет, почему я должен писать"
  • "Мне не выделяют времени специально для написания тестов, хотя это было бы полезно"
  • "Я давно пишу тесты и не понимаю, как можно без этого жить"

Автоматизированные тесты и web-программирование

Будни основной массы web-разработчиков - выбор хорошего сервера для размещения сайта. Трудно найти хостинг-провайдера (php+mysql за разумные деньги), который устроил бы сразу на 100%, а пeреезд на новый сервер даже для интерпретируемого языка, коим является мой горячо любимый PHP, может стать "фатальным". Даже в документации по Java - языке, изначально ориентированном на кроссплатформенность, написано, что цена переносимости никогда не равна нулю. Эти люди знают, что говорят. После переезда в прекрасно отлаженных и стабильно работающих ранее скриптах могут появиться warning'и, а какие-то программы перестанут работать совсем: поменялись пути, библиотеки, версия самого php.

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

Вслед за решением тестировать, приходит необходимость как-то организовать этот процесс. Например, выделить для тестовых скриптов отдельную директорию, создать программу, которая запустит все скрипты и в зависимости от их исхода напишет "OK" или "Error". Вполне возможно проделать это "с нуля", но есть готовые тестовые инфраструктуры (вспомогательные программы), которые объединяют группы тестов "по темам", единообразно их сохраняют, запускают и выводят результаты.

Cоздание тестов в phpUnit

В основном из-за увлеченности методологией XP авторы знакомы с тестовой инфраструктурой JUnit, соответственно, для php их выбор пал на phpUnit, как на созданный энтузиастами порт своего "старшего брата". На сегодняшний день существует несколько различных версий порта JUnit на php. Как минимум 3 варианта c названием phpUnit и порт php_simpletest. Регулярно обновляется версия PEAR::PHPUnit (Sebastian Bergmann). Php_simpletest находится в состоянии первой беты, другие phpUnit'ы обновлялись год назад (phpUnit project) и два года назад (phpunit-1.0.0) соответственно. Все рассмотренные ниже примеры модульных тестов написаны с использованием PEAR::PHPUnit.

Создадим набор тестов для класса Message, который форматирует и проверяет сообщение для последующей отправки его по e-mail.

Конструктор класса получает 3 параметра (имя отправителя, его e-mail aдрес и тело сообщения). Метод format_message() форматирует сообщение перед отправкой, а is_valid() проверяет возможность отправки сообщения (заполнены ли поля, и корректно ли введен е-mail). Исходный код класса Message - здесь

"Сердцем" тестирования является класс PHPUnit, который запускает TestSuite (набор тестов) и возвращает объект TestResult (результат теста).

Для того, чтобы написать минимальный набор тестов, используя phpUnit, необходимо:

  1. Подключить библиотеку PHPUnit.php
  2. Создать подкласс базового класса TestCase
  3. Добавить в него произвольное количество тестирующих методов, названия которых начинаются с "test". В нашем случае это "test_empty_input","test_email_invalid","test_valid_input". В них будут вызываться методы тeстируемого класса Message. На вход будут подаваться заранее известные параметры, а результат сравнивается с эталонным посредством семейства функций Assert, унаследованной нашим тестовым классом от TestCase (метод assertEquals проверяет ожидаемый и реально полученный результат на равенство, assertTrue проверяет, имеет ли поданный параметр значение "true" и т. д. )
  4. Cоздать класс PHPUnit_TestSuite, передав ему в качестве параметра название класса с набором тестов
  5. Запустить набор тестов и вывести результат

Создадим набор тестов для класса, следуя приведенной инструкции.

Мы протестируем следующие аспекты работы класса Message: его реакцию на пустое сообщение, и некорректный e-mail, а также сравним отформатированное объектом класса сообщение с эталонным.

Создаем сообщение, подаем на вход конструктора неверный e-mail, ожидаем, что метод класса is_valid(), ответсвенный за его проверку, возвратит 'false'.

function test_email_invalid() {
$m = new Message('name', 'invalid', 'body');
$this->assertFalse($m->is_valid()); /* ожидаем, что m->is_valid() возвращает false */
}

Создаем сообщение, подаем на вход конструктора пустые строки, ожидаем, что метод класса is_valid(), так же как и в прошлый раз вернет false.

function test_empty_input() {
$m = new Message('', '', '');
$this->assertFalse($m->is_valid()); /* ожидаем, что m->is_valid() возвращает false */
}

И, наконец, подаем на вход корректно сформированное сообщение и ожидаем, что класс его правильно сформатирует

function test_valid_input() {
$m = new Message('name', 'invalid@mail.ru', 'body');
$this->assertTrue($m->is_valid());
$valid_string = <<<EOL
from: name (invalid@mail.ru)

body
EOL;
$this->assertEquals($valid_string, $m->as_string()); /* ожидаем, что эталонная строка и результат работы as_string() совпадут */
}
}

Запускаем набор тестов (полная версия testmessage.php - здесь) и получаем следующий результат:

TestCase messagetest->test_email_invalid() passed
TestCase messagetest->test_empty_input() passed
TestCase messagetest->test_valid_input() passed

Все тесты завершились успешно. Теперь можно продолжить наращивание функциональности класса Message, будучи уверенным, что после очередной модификации он корректно работает (конечно при условии, что сработали все тесты).

Разработка класса Message и разработка Message c набором тестов не очень сильно различаются по времени, но во втором случае мы имеем мощную "поддержку" на будущее, над каждой функцией мы размышляем как минимум дважды, и позже можем легко определить работоспособность скрипта на новой программно-аппаратной конфигурации.

Гусев Антон (tony_@mail.ru)
Невоструев Иван (vanilla@mail.ru)

Материалы:

  1. Кент Бек. Экстремальное программирование. - M.: Питер, 2002.
  2. Себастьян Бергман. Домашняя страница проекта phpUnit
  3. Кирилл Максимов. Организация и именование автоматизированных тестов




 :::::  Glader пишет 02.01.2004 @ 23:38 
Функциональные тесты - это замечательно. А вот как тестировать, например, общий вид? Допустим, есть два модуля. Один извлекает и собирает информацию, а другой на ее основе сооружает html-страницу. Тестирование первого из них у Вас хорошо описано. А вот как быть со вторым? Ведь при каждой смене дизайна он будет менять результат. Похоже, придется либо полностью ему довериться, либо иметь тестовый дизайн, на котором все и обкатывать. Кто предложит более удобный вариант?

 :::::  Антон пишет 03.01.2004 @ 00:54 
Начнем с того, что Вы наверняка пользуетесь каким-то стандартным шаблонным движком
(fast template, smarty) или написали свой. Я уверен, что возможна модификация вашего
шаблонного движка таким образом, чтобы он окружал подставляемые переменные HTML комментариями. Тесты такого модуля состоят в том, что нужно открыть соединение на
80 порт (это Вы прекрасно знаете), сделать GET скрипту и после искать комментарии
специального вида внутри полученного HTML. Так я проверял наличие всех нужных мне переменных на странице, безотносительно к текущей версии дизайна.
В связке XML+XSL(t) это выглядит похоже.

Достаточна ли такая проверка для Ваc?
 :::::  Michael Elfimov пишет 08.01.2004 @ 13:36 
Тестирования внешнего вида - это не только тестирования сгенерированного HTML на корректность, большинство сайтов включают в себя клиентский код на JavaScript, и в целом функционирование страницы не так-то просто описать такого рода тестом. Допустим, я проконтролировал наличие необходимых элементов на странице (код в комментариях - хорошая мысль, спасибо за неё), но несмотря на это страница может не работать из-за некорректного отображения её браузером. Тут открывается проблема тестирования интерфейса, а вот тут с автоматическими тестами гораздо сложнее, между тем под тестированием сгенерённого HTML подразумевается скорее именно тестирование интерфейса.
Короче, к чему это всё я: поделитесь опытом организации такого тестирования, если он есть. Может фреймворки какие есть почти готовые, или сайты на такую тему, в общем скажите чего-нибудь.
 :::::  sarutobi пишет 17.01.2004 @ 11:47 
cut---
Тестирования внешнего вида - это не только тестирования сгенерированного HTML на корректность, большинство сайтов включают в себя клиентский код на JavaScript
cut---
напишите отдельный модуль на JS, убедитесь в том что он работает и не парьтесь.
Среда для тестирования JS (а так же большинства известных языков, включая HTML, XML XSL) доступна по адресу www.xprogramming.com раздел Software :)))
Вообще же TDD(Test driven developing) - это тольо 50% успеха проекта. Остальные 50% -- это не вошедшие в статью практики eXtreme Programming. Подробнее смотрите
xprogramming.com.ua
xprogramming.ru


Имя:
Email:
URL

Введите сумму двух чисел девять и одинн (девять+одинн=?)
Запомнить мою информацию

* Html запрещен* Ваш E-mail опубликован не будет.

Copyright © 2000-2001 WebScript.Ru nas@webscript.ru
Design © 2001 by Parallax Design Studio (aka Spectator.ru)
Все торговые марки и авторские права на эту страницу принадлежат их соответствующим владельцам.
Сгенерировано за: 0.0124111