![](/user_photo/2706_HbeT2.jpg)
PHP5_nachinayushim
.pdf![](/html/2706/356/html_7o_ZwAhYkF.IEn3/htmlconvd-YZt_5u671x1.jpg)
Учебный пример: диспетчер протоколирования на PHP 673
<?php
require_once ("../settings-test.php"); require_once ("class.UserLog.php"); require_once ("phpunit/phpunit.php");
class TestUserLog extends TestCase { private $ulGood = null;
private $ulBad = null;
Затем определяется специфический контекст, в котором будут выполняться тесты. Это делается путем определения значений в PHPUnit+функции setUp(). В данном случае создается два UserLog+объекта:
function setUp()
{
$this->ulGood = new UserLog (
array ('site' |
=> 1, |
'section' |
=> 2, |
'login' |
=> "3", |
'session' |
=> "1E23553", |
'firstname' |
=> "Alice", |
'lastname' |
=> "AppleGate", |
'address1' |
=> "123Main", |
'city' |
=> "Sandusky", |
'state' |
=> "OH", |
'zip' |
=> "44870", |
'demo0' |
=> "21", |
'demo1' |
=> "15", |
'demo2' |
=> "22", |
'demo3' |
=> "26")); |
$this->ulBad = new UserLog ( |
|
array ('site' |
=> 0, |
'section' |
=> 0, |
'login' |
=> "", |
'session' |
=> "1E23553", |
'firstname' |
=> "Alice", |
'lastname' |
=> "AppleGate", |
'address1' |
=> "123Main", |
'city' |
=> "Sandusky", |
'state' |
=> "OH", |
'zip' |
=> "44870", |
'demo0' |
=> "21", |
'demo1' |
=> "15", |
'demo2' |
=> "22", |
'demo3' |
=> "26")); |
} |
|
Необходимо определить тестовые функции.
Первая функция, testValid0(), использует PHPUnit+функцию assertEquals() для проверки следующих условий:
Sandusky ++++++ город, представленный в UserLog+объекте $ulGood; $ulGood ++++++ корректный журнал;
$ulGood не имеет недостоверных данных.
Если тесты выполняются, то контекст, в котором они работают (по крайней мере, для объекта $ulGood), работает корректно. Чтобы изучить код функции assertEquals(), необходимо просмотреть файл phpunit.php из инсталляции PHPUnit:
![](/html/2706/356/html_7o_ZwAhYkF.IEn3/htmlconvd-YZt_5u672x1.jpg)
674 Глава 17
function testValid0()
{
$this->assertEquals("Sandusky", $this->ulGood->city, "invalid city"); $this->assertEquals(true, $this->ulGood->isValid(), "valid log"); $this->assertEquals(0, count ($this->ulGood->getInvalidData()),
"valid count");
}
В следующем тесте создается новый UserLog+объект, $ul, и заполняется некото+ рыми некорректными данными (а именно значением site). Формулируется утвержде+ ние, что функция isValid() вернет значение false, и что количество некорректных элементов будет равно 1. Если эти тесты выполняются верно, то можно быть уверен+ ным, что программа правильно выбирает недостоверные данные внутри объектов:
function testInvalid0() |
|
|
|
{ |
|
|
|
$ul = new UserLog (array ('site' |
=> 0, |
|
|
'section' |
|
=> 9, |
|
'login' |
|
=> |
"user101", |
'session' |
=> |
"1E23553", |
|
'firstname' => |
"Alice", |
||
'lastname' |
=> |
"AppleGate", |
|
'address1' |
=> |
"123Main", |
|
'city' |
|
=> |
"Sandusky", |
'state' |
|
=> |
"OH", |
'zip' |
|
=> |
"44870", |
'demo0' |
|
=> |
"21", |
'demo1' |
|
=> |
"15", |
'demo2' |
|
=> |
"22", |
'demo3' |
|
=> |
"26")); |
$this->assertEquals(false, $ul->isValid(), "valid ul"); $this->assertEquals(1, count ($ul->getInvalidData()), "valid site");
}
Третий тест также проверяет объект $ulBad. Используются утверждения о том, что данные недостоверны и что количество некорректных элементов равно трем:
function testInvalid1()
{
$this->assertEquals(false, $this->ulBad->isValid(), "invalid ul"); $this->assertEquals(3, count ($this->ulBad->getInvalidData()),
"invalid site, section, and login");
}
Предыдущие тесты обрабатывали имеющиеся данные, содержащиеся внутри объек+ тов. Однако как проверить следующий этап, т.е. сохранение объектов в базе данных? Для этого, естественно, придется разработать еще несколько тестов. В следующем тесте используется блок try-catch, а также метод assert(). Тест представляет собой по+ пытку отправить в базу данных информацию, содержащуюся в объекте $ulGood; если попытка удалась, то ошибок нет и утверждение истинно. В противном случае методу assert() передается значение false, а на экран выводится сообщение об ошибке.
Следует заметить, что метод assert() не используется для отображения сообще+ ния об ошибке. Это связано с тем, что желательно получить более подробное описа+ ние возникшей ошибки. Поэтому в данном случае используется сообщение, сгенери+ рованное в блоке try:
![](/html/2706/356/html_7o_ZwAhYkF.IEn3/htmlconvd-YZt_5u673x1.jpg)
Учебный пример: диспетчер протоколирования на PHP 675
function testGoodPersist0()
{
try { $this->ulGood->persist(); $this->assert(true);
} catch (MultiLogException $e) { $this->assert(false);
print ($e->getErrorMessage());
}
}
Теперь следует точно так же проверить объект $ulBad. Естественно, ожидается, что проверка выдаст отрицательный результат, поэтому утверждения необходимо со+ ответствующим образом изменить:
function testBadPersist0()
{
try {
$this->ulBad->persist();
$this->assert(false); // здесь должен быть сбой } catch (MultiLogInvalidDataException $e) {
$this->assert(true);
}
}
Конечно, программа не должна сохранять один и тот же объект дважды в одной строке. Чтобы протестировать такую ситуацию, следует сформулировать утверждение о том, что вторая попытка сохранения не удалась. После этого вторая попытка сохра+ нения приведет к возникновению исключения, и это можно будет использовать для формулировки правильного утверждения:
function testBadPersist1()
{
try { $this->ulGood->persist(); $this->assert(true);
$this->ulGood->persist();
$this->assert(false); // здесь должен быть сбой
}catch (MultiLogInvalidDatabaseException $e) { $this->assert(true);
}catch (MultiLogDatabaseQueryException $e) {
$this->assert(false); // неверное утверждение
}
}
А что если приложение работает не так, как должно? Например, в коде была слу+ чайно допущена опечатка. Чтобы проверить это, вставим намеренно слово ‘‘where’’ в значение сеанса. При попытке сохранения таких данных должно быть сгенерирова+ но исключение.
В блоке catch результат метода $ul->persist() ошибочно принимается равным true. Это должно привести к отрицательному результату тестирования (вывод будет показан в конце этого раздела):
function testBadPersist2_fail() |
|
{ |
|
$ul = new UserLog(array('site' |
=> "1", |
'section' => "9",
![](/html/2706/356/html_7o_ZwAhYkF.IEn3/htmlconvd-YZt_5u674x1.jpg)
676 Глава 17
'login' => "user101",
'session' => "1' where '1' and '1"));
try {
$ul->persist();
$this->assert(false); // здесь должен быть сбой } catch (MultiLogDatabaseQueryException $e) {
$this->assert(true);
}
}
Это, конечно, не единственный способ использования утверждений. В следующем примере показано, как вставить в метод assert() любой оператор ++++++ при условии, что он возвращает булево значение. Кроме того, в этом примере метод assert()используется для вывода сообщения об ошибке.
В целях эксперимента сформируем некорректный SQL+оператор. Например, мож+ но заменить слово ‘‘insert’’ на ‘‘inert’’:
function testSqlGeneration0()
{
$this->assert(
strpos (" ".$this->ulGood->toSQL(), "insert into user_log(visit_date,
visit_time, site_id, demo_id, login_id, session, firstname,
lastname, address1, address2, city, state, zip )") > 0, "invalid SQL generation first");
$this->assert(
strpos (" ".$this->ulGood->toSQL(), "1, 2, '3', '1E23553', 'Alice', 'AppleGate', '123Main', ", 'Sandusky', 'OH',
'44870' )") > 0, "invalid SQL generation last");
}
Теперь проверим два других метода ++++++ функции toHTML() и getDemographics(). В формулировке утверждений для этого теста нет ничего нового:
function testHtmlGeneration0 ()
{
$this->assert(strpos (" ".$this->ulGood->toHTML(), "<tr") > 0); $this->assert(strpos ($this->ulGood->toHTML(), ">AppleGate</td><td")
> 0);
}
function testDemo0 ()
{
$this->assertEquals(4, count($this->ulGood->getDemographics())); $this->assertEquals(4, count($this->ulBad->getDemographics()));
}
В последнем тесте заново создается база данных, снова сохраняется объект $ulGood, а затем база данных опрашивается вручную, чтобы определить количество возвращенных значений. Этот тест подтверждает результаты предыдущего теста:
function testDemo1 ()
{
include ("../logs/initialize.php"); // заново создаем базу
try { $this->ulGood->persist(); $this->assert(true);
![](/html/2706/356/html_7o_ZwAhYkF.IEn3/htmlconvd-YZt_5u675x1.jpg)
![](/html/2706/356/html_7o_ZwAhYkF.IEn3/htmlconvd-YZt_5u676x1.jpg)
678 Глава 17
Рис. 17.5.
class TestLogContainer extends TestCase { function setUp()
{include ("../logs/initialize.php"); // заново создаем базу $ul0 = new UserLog (
array ('site' |
=> "1", |
'section' |
=> "111", |
'login' |
=> "aapple", |
'session' |
=> "1E23553", |
'firstname' |
=> "Aurthor", |
'lastname' |
=> "Andersen", |
'address1' |
=> "123 Main St.", |
'city' |
=> "Sandusky", |
'state' |
=> "OH", |
'zip' |
=> "44870", |
'demo0' |
=> "21", |
'demo1' |
=> "15", |
'demo2' |
=> "22", |
'demo3' |
=> "26")); |
$ul0->persist(); |
|
![](/html/2706/356/html_7o_ZwAhYkF.IEn3/htmlconvd-YZt_5u677x1.jpg)
Учебный пример: диспетчер протоколирования на PHP 679
$ul1 = new UserLog ( |
|
array ('site' |
=> "1", |
'section' |
=> "112", |
'login' |
=> "bbarker", |
'session' |
=> "3F398", |
'firstname' |
=> "Blob", |
'lastname' |
=> "Barker", |
'address1' |
=> "100 Hollywood Blvd.", |
'city' |
=> "LA", |
'state' |
=> "CA", |
'zip' |
=> "90036", |
'demo0' |
=> "78", |
'demo1' |
=> "21", |
'demo2' |
=> "12", |
'demo3' |
=> "7")); |
$ul1->persist(); |
|
$ul2 = new UserLog ( |
|
array ('site' |
=> "2", |
'section' |
=> "200", |
'login' |
=> "ccabbage", |
'session' |
=> "L33T", |
'firstname' |
=> "Capitan", |
'lastname' |
=> "Cabbage", |
'address1' |
=> "55 Broadway", |
'city' |
=> "NYC", |
'state' |
=> "NY", |
'zip' |
=> "10001", |
'demo0' |
=> "14", |
'demo1' |
=> "15", |
'demo2' |
=> "41", |
'demo3' |
=> "0")); |
$ul2->persist(); |
|
}
Имея специфический контекст, можно создать тест. Для этого примера включает+ ся только один тест. Он создает новый LogContainer+объект, содержащий все UserLog+ объекты, поступающие с сайта 1:
function testContainerValid0()
{
try {
$lc = new LogContainer ("", "", "1", "");
Зная контекст, сформулируем утверждение о том, что внутри LogContainer со+ держится только два UserLog+объекта:
$this->assertEquals(2, $lc->getCount(), "count");
Затем создается утверждение о том, что два UserLog+объекта, содержащиеся в LogContainer, имеют регистрационные имена aapple и bbarker соответственно:
$logs = $lc->getUserLogs();
$this->assert(strcmp ($logs[0]->getLogin, "aapple"), "login_id incorrect a");
$this->assert(strcmp ($logs[0]->getLogin, "bbarker"), "login_id incorrect b");
} catch (MultiLogException $e) { $this->assert(false);
print $e->getErrorMessage();
![](/html/2706/356/html_7o_ZwAhYkF.IEn3/htmlconvd-YZt_5u678x1.jpg)
680 Глава 17
}
}
}
Наконец, создается и запускается тестовый комплект:
$suite = new TestSuite;
$suite->addTest(new TestLogContainer("testContainerValid0"));
$testRunner = new TestRunner(); $testRunner->run( $suite );
В браузере результат работы этого сценария должен выглядеть аналогично рис. 17.6.
Рис. 17.6.
Последний тестовый класс проверяет демографические данные в UserLog+ объектах. Сначала подключаются необходимые файлы:
<?php
require_once ("../settings-test.php"); require_once ("class.UserDemographic.php"); require_once ("phpunit/phpunit.php");
Объявление класса начинается с определения переменных, в которых будут хра+ ниться UserDemographic+объекты. Кроме того, объявляется функция intializeDb(), которая будет использоваться для повторного заполнения базы данных ++++++ это позво+ лит переустанавливать контекст:
class TestUserDemographic extends TestCase {private $demoGood = null;
private $demoBad = null;
function initializeDb () {
include "../logs/initialize.php";
}
![](/html/2706/356/html_7o_ZwAhYkF.IEn3/htmlconvd-YZt_5u679x1.jpg)
Учебный пример: диспетчер протоколирования на PHP 681
Затем контекст инициализируется ++++++ следует заметить, что демографические дан+ ные содержатся только в последних элементах массива, поэтому можно спокойно иг+ норировать первые элементы каждого UserLog+объекта:
function setUp() |
|
|
{ |
|
|
$this->demoGood = new UserDemographic ( |
// игнорируется |
|
array ('id' |
=> 1, |
|
'site' |
=> 1, |
// игнорируется |
'section' |
=> 2, |
// игнорируется |
'login' |
=> "3", |
// игнорируется |
'session' |
=> "1E23553", |
// игнорируется |
'firstname' |
=> "Alice", |
// игнорируется |
'lastname' |
=> "AppleGate", |
// игнорируется |
'address1' |
=> "123Main", |
// игнорируется |
'city' |
=> "Sandusky", |
// игнорируется |
'state' |
=> "OH", |
// игнорируется |
'zip' |
=> "44870", |
// игнорируется |
'demo' |
=> "21", |
|
'demo1' |
=> "15", |
|
'demo2' |
=> "22", |
|
'demo3' |
=> "26")); |
|
$this->demoBad = new UserDemographic ( |
// игнорируется |
|
array ('site' |
=> 1, |
|
'section' |
=> 2, |
// игнорируется |
'login' |
=> "3", |
// игнорируется |
'session' |
=> "1E23553", |
// игнорируется |
'firstname' |
=> "Alice", |
// игнорируется |
'lastname' |
=> "AppleGate", |
// игнорируется |
'address1' |
=> "123Main", |
// игнорируется |
'city' |
=> "Sandusky", |
// игнорируется |
'state' |
=> "OH", |
// игнорируется |
'zip' |
=> "44870", |
// игнорируется |
'demo1' |
=> "15", |
|
'demo2' |
=> "22", |
|
'demo3' |
=> "26")); |
|
} |
|
|
|
|
|
Первый тест для UserDemographic+объектов выглядит так:
function testValid0()
{
$this->assertEquals(null, $this->demoGood->city, "invalid city"); $this->assertEquals("21", $this->demoGood->demo, "invalid demo0"); $this->assertEquals(null, $this->demoGood->demo1, "invalid demo1"); $this->assertEquals(null, $this->demoGood->demo2, "invalid demo2"); $this->assertEquals(null, $this->demoGood->demo3, "invalid demo3"); $this->assertEquals(null, $this->demoGood->demo4, "invalid demo4"); $this->assertEquals(true, $this->demoGood->isValid(), "valid log"); $this->assertEquals(0, count ($this->demoGood->getInvalidData()),
"valid count");
}
Приведенный ниже тест позволяет убедиться, что предположительно недосто+ верные данные действительно недостоверны:
function testInvalid0()
{
$this->assertEquals(false, $this->demoBad->isValid(), "invalid log"); $this->assertEquals(1, count ($this->demoBad->getInvalidData()),
"expecting 1 invalid item");
}
![](/html/2706/356/html_7o_ZwAhYkF.IEn3/htmlconvd-YZt_5u680x1.jpg)
682 Глава 17
Наконец, создается тест для проверки возможности сохранения объекта в базе данных:
function testGoodPersist0()
{
$this->initializeDb(); try {
$this->demoGood->persist(); $this->assert(true);
} catch (MultiLogException $e) { $this->assert(false);
print ($e->getErrorMessage());
}
}
}
В конце используется уже знакомый код:
$suite = new TestSuite;
$suite->addTest(new TestUserDemographic("testValid0")); $suite->addTest(new TestUserDemographic("testInvalid0")); $suite->addTest(new TestUserDemographic("testGoodPersist0"));
$testRunner = new TestRunner(); $testRunner->run( $suite );
Результат работы тестов показан на рис. 17.7.
Рис. 17.7.
Стоит отметить, что пакет PHPUnit содержит множество других функций. В главе были описаны функции, с помощью которых можно начинать работу с пакетом, но можно использовать и другие функции для создания необходимых тестов ++++++ изучение этих функций остается в качестве упражнения читателям.