Архив метки: Zend_Test

Zend Framework: модульное тестирование с помощью Zend_Test и PHPUnit

Задачи:

  1. Изучить основы TDD — test-driven development — разработка через тестирование
  2. Воспользоваться на практике TDD в приложении, построенном на Zend Framework, с помощью Zend_Test и PHPUnit

Решение:

Первая задача, решается довольно просто — читаем соответствующую литературу. Мне в этом сильно помог перевод статьи Томаса и Ханта «Учимся любить юнит-тестирование».

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

Юнит-тестирование силами Zend_Test и PHPUnit

Сначала необходимо поставить сам фреймворк PHPUnit. Он входит в состав пакетов PEAR, поэтому сначала необходимо будет поставить сам PEAR. В debian системах делается это так:

apt-get install php-pear

Далее действуем по довольно короткому мануалу с сайта PHPUnit.

Далее, если вы создавали Zend Framework проект с помощью командной строки, то могли обнаружить следующую, казалось бы, лишнюю структуру папок и файлов:

screen-test-folders

Эти файлы пригодятся нам для тестов.

Первым делом заполняем файл phpunit.xml — конфигурационный файл для PHPUnit. Я почти полностью взял его из этой статьи:

<?xml version="1.0" encoding="UTF-8" ?>
<phpunit bootstrap="./application/bootstrap.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnFailure="true"
syntaxCheck="true">

    <!-- запускаем все тесты из корневой директории -->
    <testsuite name="Main Test Suite">
        <directory>./</directory>
    </testsuite>

    <filter>
    <!-- не смотрим на следующие директории -->
        <blacklist>
            <directory suffix=".php">/usr/share/php</directory>
            <directory suffix=".php">../tests</directory>
        </blacklist>
       <!-- смотрим лишь на следующие директории -->
       <whitelist>
           <directory suffix=".php">../application</directory>
                <exclude>
                      <directory suffix=".phtml">../application</directory>
                       <file>../application/Bootstrap.php</file>
                </exclude>
        </whitelist>
    </filter>
    <logging>
         <!-- логирование и создание отчета -->
         <log type="coverage-html" target="./log" charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70"/>
    </logging>
</phpunit>

Далее, в файл /test/application/bootstrap.php практически полностью копируем оригинальный index.php из основного приложения:

<?php
error_reporting(E_ALL | E_STRICT);
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../../application'));

// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

// Ensure library/ is on include_path
set_include_path(realpath('/var/www/libraries/ZF-1.9.7/library') . PATH_SEPARATOR
. get_include_path());

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

require_once 'ControllerTestCase.php';

Как видно, в конце мы включаем файл, которого еще нет. Исправим оплошность и создадим файл /tests/application/ControllerTestCase.php:

<?php

abstract class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{

    public function setUp() {
         // Assign and instantiate in one step:
         $this->bootstrap = new Zend_Application(
                                  APPLICATION_ENV,
                                  APPLICATION_PATH . '/configs/application.ini'
                            );
         parent::setUp();
     }
}

Класс у нас абстрактный, поскольку послужит основой для всех остальных тестов, связанных с контроллером.

Ну и последнее, сам тест. Создадим папку и файл /test/application/controllers/IndexControllerTest.php.  Рекомендую придерживаться оригинальной структуры приложения, чтобы в будущем, когда будет много тестов, не происходило путаницы с их месторасположением. Содержимое нашего файла с тестами:

<?php
class IndexControllerTest extends ControllerTestCase {
      public function testTestAction() {
           # "Идем" в корень сайта
           $this->dispatch('/');
           # Проверяем, стоит ли у нас IndexController?
           $this->assertController('index');
           # Проверяем, запущенно ли indexAction?
           $this->assertAction('index');
      }
}

И, соответственно, долгожданный запуск первого теста. Для этого в консоли необходимо попасть в папку /tests/ и выполнить команду phpunit. Автоматически подхватится файл конфигурации phpunit.xml и пойдут тесты. Если мы ничего не напутали раньше, то в консоли должен получиться примерно такой результат:


PHPUnit 3.4.10 by Sebastian Bergmann.
Time: 0 seconds, Memory: 11.25Mb
OK (1 test, 2 assertion)

Поздравляю, самое сложно позади.) Осталось только разобраться, какие есть методы для тестирования и как ими пользоваться. Перечислять их всех и проводить по каждому тест — дело, очевидно, неблагодарное.) Поэтому скажу лишь, что суть (или как написали в мануале, «сердце») юнит-тестирования в запуске функции с определенными параметрами, при этом с указанием ожидаемого результата. Если ожидания сошлись с действительностью — OK, а вот если нет — поздравляю, вы не зря писали тест!)