Статьи

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

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

Позже, Мэтью услужливо написал статью о том, как использовать это, и я использовал это как отправную точку для информации здесь. (Спасибо, Мэтью!)

Я использую проект TodoIt , простое демонстрационное приложение ZF, которое требует модульных тестов.

Настройка PHPUnit

Все ваши юнит-тесты будут жить в папке / tests. Инструмент ZF cli создаст для вас файл phpunit.xml, но вы обнаружите, что он пуст! Вот как это должно выглядеть:

<phpunit colors="true" bootstrap="./TestHelper.php">
<testsuite name="TodoIt Test Suite">
<directory>./</directory>
</testsuite>

<filter>
<whitelist>
<directory suffix=".php">../library/</directory>
<directory suffix=".php">../application/</directory>
<exclude>
<directory suffix=".phtml">../application/</directory>
</exclude>
</whitelist>
</filter>

<logging>
<log highlowerbound="80" lowupperbound="50" highlight="true" yui="true" charset="UTF-8" target="./log/report" type="coverage-html"></log>
</logging>

</phpunit>

 

Этот файл используется для настройки самого phpunit и избавляет от необходимости использовать параметры командной строки. Поскольку это XML, его довольно легко читать. Элемент testsuites используется для указания тестового набора, который мы собираемся протестировать. В принципе, вы можете иметь много тестовых наборов; в этом случае достаточно одного! Раздел фильтра используется для указания того, какие файлы использовать для отчетов о покрытии кода, а раздел ведения журнала — для настройки отчетов.

Мы также указываем TestHelper.php в качестве начальной загрузки. Это означает, что он вызывается для нас и содержит необходимые настройки PHP, которые нам нужно сделать, чтобы загрузить и использовать Zend Framework. В действительности TestHelper.php действует так же, как public / index.php для вашего веб-приложения. TestHelper.php выглядит так:

<?php
// Based on http://weierophinney.net/matthew/archives/190-Setting-up-your-Zend_Test-test-suites.html

// PHP settings
error_reporting(E_ALL | E_STRICT);
date_default_timezone_set('Europe/London');

define('APPLICATION_ENV', 'unittesting');
define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

// Directories for include path
$root = realpath(dirname(__FILE__) . '/../');
$library = $root . '/library';
$models = $root . '/application/models';

$path = array(
$library,
$models,
get_include_path()
);
set_include_path(implode(PATH_SEPARATOR, $path));

require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();

// Unset global variables
unset($root, $library, $models, $path);

Как и в случае с public / index.php, мы устанавливаем APPLICATION_ENV и APPLICATION_PATH, обновляем include_path и затем устанавливаем автозагрузчик. Теперь мы все готовы написать несколько тестов!

Тестовый класс контроллера

Я помещаю свои тестовые классы контроллера в тесты / приложения / контроллеры, чтобы их было легко найти. (Тесты моделей идут в тестах / приложениях / моделях!). Приложение TodoIt имеет форму входа в AuthController :: indexAction (), доступ к которой осуществляется через URL / auth. Начнем с тестирования этой формы.

Тестовый класс контроллера называется AuthControllerTest и находится в tests / application / controllers / AuthControllerTest.php:

<?php

// Call AuthControllerTest::main() if this source file is executed directly.
if (!defined("PHPUnit_MAIN_METHOD")) {
define("PHPUnit_MAIN_METHOD", "AuthControllerTest::main");
}

require_once 'PHPUnit/Framework/TestCase.php';

/**
* @group Controllers
*/
class AuthControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
public static function main()
{
$suite = new PHPUnit_Framework_TestSuite(get_class($this));
$result = PHPUnit_TextUI_TestRunner::run($suite);
}

public function setUp()
{
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);

$this->bootstrap = $application;
return parent::setUp();
}

public function tearDown()
{
/* Tear Down Routine */
}

public function testLoginDisplaysAForm()
{
$this->dispatch('/auth/index');
$this->assertQueryContentContains('h1', 'Login');
$this->assertQuery('form#login'); // id of form
}
}

 

Здесь происходит три вещи, поэтому давайте посмотрим на каждую по очереди.

Во-первых, мы настроили файл, чтобы разрешить PHPUnit запускать этот файл самостоятельно, используя командную строку:

phpunit tests\application\controllers\AuthControllerTest.php

Это делается путем установки константы PHPUnit_MAIN_METHOD для статического метода AuthControllerTest :: main (). Затем инструмент phpunit cli запустит этот метод, который, в свою очередь, запустит этот файл как набор тестов.

Методы setUp () и tearDown () вызываются до и после каждого тестового метода и используются, чтобы гарантировать, что у нас есть чистый лист для каждого. Поскольку мы расширились от Zend_Test_PHPUnit_ControllerTestCase, а не от PHPUnit_Framework_TestCase, мы можем использовать функциональность, специально предназначенную для упрощения тестирования контроллеров. Мы используем это в setUp (), чтобы установить для свойства bootstrap экземпляр Zend_Application, который затем используется в самих тестах.

Каждый тест — это метод, начинающийся со слова test, например:

    public function testLoginDisplaysAForm()
{
$this->dispatch('/auth/index');
$this->assertResponseCode(200);
$this->assertQueryContentContains('h1', 'Login');
$this->assertQuery('form#login'); // id of form
}

Мы начинаем с вызова dispatch (), чтобы выполнить правильное действие, а затем используем различные методы assert, чтобы проверить, что результат — это то, что мы ожидаем. Метод assertResponseCode проверяет, что мы не ошиблись, так как errorController установит код на 500 или 404. Затем мы можем использовать методы assertQuery, чтобы проверить, что было обработано в объекте ответа. Они используют пути DOM для выбора определенного элемента. Вызов assertQueryContentContains позволяет нам проверить, что текст в элементе H1 — это то, что мы ожидаем, и assertQuery просто проверяет, находится ли элемент на странице.

Вот и все.

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