Юнит тестирование приложений на Zend Framework’е

Zend Framework - Test Passed

Если вы изучаете PHP больше года, то, наверняка, уже сталкивались с юнит тестированием, и даже писали тесты, ну а в этой статье я приведу лишь “рецепт” для быстрого приготовления тестов на Zend Framework’е.

Установка

Для тестирование приложений на Zend Framework’е используется компонент самого фреймворка Zend_Test, который в свою очередь является лишь потомком PHPUnit’a, и вот его нам надо будет еще установить, детально процесс установки PHPUnit’a описан на домашней странице проекта: Chapter 3. Installing PHPUnit, тут выложу лишь краткий пересказ:

Первый способ заключается в использовании PEAR инсталлера:

1
2
pear channel-discover pear.phpunit.de
pear install phpunit/PHPUnit

Второй – вручную:

  • скачиваем архив с страницы https://phpunit.de/ и распаковываем его в папку, которая включена в include_path (см. php.ini)
  • переименовываем phpunit.php в phpunit
  • заменяем строку @php_bin@ на путь к PHP (например /usr/bin/php)
  • закидываем этот файл ко всем бинарникам, и выполняем команду chmod +x phpunit
  • в файле PHPUnit/Util/Fileloader.php заменяем строку @php_bin@ на путь к PHP (например /usr/bin/php)

Структура проекта

Приведу пример структуры каталога для проекта созданного с использование Zend_Tool (дабы не заблудиться, структура каталога tests напоминает структуру всего приложения):

project
|-- application
|-- data
|-- docs
|-- library
|-- public
`-- tests
    |-- application
    |   |-- models
    |   |   `-- PageTest.php
    |   |-- controllers
    |   |   |-- IndexControllerTest.php
    |   |   `-- ErrorControllerTest.php
    |   |-- ControllerTestCase.php
    |   `-- bootstrap.php
    |-- library
    |   `-- bootstrap.php
    `-- phpunit.xml

Кто забыл – проект создаем следующим образом:

1
zf create project zf-project

Конфигурационный файл phpunit.xml

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

1
$~/zf-project/tests/phpunit ./

Описание настроек см. в документации

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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>
            <directory suffix=".php">../library</directory>
            <exclude>
                <directory suffix=".phtml">../application</directory>
                <file>../application/Bootstrap.php</file>
            </exclude>
        </whitelist>
    </filter>   
    <logging>
        <!-- логирование и создание отчета -->
        <log type="coverage-html" target="./report" charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70"/>
    </logging>
</phpunit>

Инициализация в файле bootstrap.php

В файле phpunit.xml указан bootstrap файл, он отвечает за загрузку нашего приложения, и лишь немногим отличается от привычного index.php:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?php
// 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') : 'testing'));
 
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    get_include_path(),
)));
 
/** Zend_Application */
require_once 'Zend/Application.php';
require_once 'ControllerTestCase.php';
[/code]
 
<h3>ControllerTestCase.php</h3>
Класс ControllerTestCase является предком для всех тесткейсов:
 
[code lang="php"]
<?php
require_once 'Zend/Application.php';
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';
 
abstract class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
    /**
     * @var Zend_Application
     */
    protected $_application;
 
    public function setUp()
    {
        // указываем функцию, которая будет выполнена до запуска тестов
        $this->bootstrap = array($this, 'appBootstrap');
        parent::setUp();
    }
 
    public function appBootstrap()
    {
        // инициализируем наше приложение
        $this->_application = new Zend_Application(
            APPLICATION_ENV,
            APPLICATION_PATH . '/configs/application.ini'
        );
         
        $this->_application->bootstrap();
    }
}

Написание Тестов

Первый блин

Стоит начать с минимума – проверим, что у нас тесты запускаются и работают, создадим простой тест:

1
2
3
4
5
6
7
class IndexControllerTest extends ControllerTestCase
{
    public function testTestAction()
    {
        $this->assertTrue(true);
    }
}

Если мы ничего не забыли, то увидим что-то вроде:

PHPUnit 3.4.0beta3 by Sebastian Bergmann.
Time: 0 seconds
OK (1 tests, 1 assertions)
Generating code coverage report, this may take a moment.

Еще чуть-чуть блинов

Теперь немного усложним задачу – будем проверять, туда ли мы попали, для этого будем использовать следующие методы:

  • dispatch – указываем URL куда идем
  • assertModule – проверяем тот ли модуль, который нам нужен
  • assertController – проверяем контроллер
  • assertAction – проверяем экшен
01
02
03
04
05
06
07
08
09
10
class IndexControllerTest extends ControllerTestCase
{
    public function testIndexAction()
    {
        $this->dispatch('/');
        $this->assertModule('default');
        $this->assertController('index');
        $this->assertAction('index');
    }
}

Тоже самое сделаем для ErrorController’а:

01
02
03
04
05
06
07
08
09
10
class ErrorControllerTest extends ControllerTestCase
{
    public function testErrorURL()
    {
        $this->dispatch('foo');
        $this->assertModule('default');
        $this->assertController('error');
        $this->assertAction('error');
    }
}

Запускаем тесты:

PHPUnit 3.4.0beta3 by Sebastian Bergmann.
Time: 0 seconds
OK (3 tests, 7 assertions)
Generating code coverage report, this may take a moment.

Можно теперь взглянуть на отчет – для этого идем по адресу http://%project%/tests/reports/ и тама мы должны увидеть что-то вроде:
PHPUnit Coverage

Если вы ничего не увидели – значит – либо директория tests/reports не writable, либо XDebug у вас не установлен.

Проверяем DOM

Теперь создадим новый экшен:

1
zf create action about index

Добавим функционала для вывода сообщения во view:

01
02
03
04
05
06
07
08
09
10
11
public function aboutAction()
 {
     // action body
     $message = $this->_getParam('m');
      
     if ($message) {
         $this->view->message = $message;
     } else {
         $this->view->message = "no message";
     }
}

Изменим представление:

1
<h2 id="message"><?= $this->message ?></h2>

Напишем еще немного тестов:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class IndexControllerTest extends ControllerTestCase
{
    // проверяем что данный экшен доступен
    public function testAboutAction()
    {
        $this->dispatch('/index/about');
        $this->assertModule('default');
        $this->assertController('index');
        $this->assertAction('about');
    }
 
    // проверяем поведение экшена по умолчанию
    public function testAboutNoMessageAction()
    {
        $this->dispatch('/index/about');
        $this->assertModule('default');
        $this->assertController('index');
        $this->assertAction('about');       
        $this->assertResponseCode(200);
         
        // на странице должен присутствовать элемент с ID="messages" в количестве 1 штука
        $this->assertQueryCount('#message', 1);
 
        // и в нем должен быть текст "no message"
        $this->assertQueryContentContains('#message', "no message");
    }
 
    // проверяем поведение экшена при входящих параметрах
    public function testAboutWithMessageAction()
    {
        $this->dispatch('/index/about/m/true-lya-lya');
        $this->assertModule('default');
        $this->assertController('index');
        $this->assertAction('about');       
        $this->assertResponseCode(200);
         
        $this->assertQueryCount('#message', 1);
 
        // текст теперь должен быть "true-lya-lya"
        $this->assertQueryContentContains('#message', "true-lya-lya");
    }
 
    // альтернативный способ передачи параметров в реквест
    // данный тест дублирует предыдущий
    public function testAboutWithMessageAltAction()
    {
        $this->getRequest()
             ->setParams(array("m" => "true-lya-lya"))
             ->setMethod('GET');
              
        $this->dispatch('/index/about/');
        $this->assertModule('default');
        $this->assertController('index');
        $this->assertAction('about');       
        $this->assertResponseCode(200);
         
        $this->assertQueryCount('#message', 1);
        $this->assertQueryContentContains('#message', "true-lya-lya");
}

Описание assert’ов по DOM’у можно найти в документации:

Тестирование аутентификации пользователей

Для начала нам понадобиться таки написать простую систему аутентификации, создадим новый контроллер Login:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
<?php
/**
 * PagesController for default module
 *
 * @category Application
 * @package Default
 */
class LoginController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $this->view->login = false;
         
        // проверка не залогинен ли пользователь
        if (!Zend_Auth::getInstance()->getIdentity()) {
             
            // берем форму логина и закидываем во view
            $form = $this->_getLoginForm();
            $this->view->form = $form;
     
            // если форма была отправлена, мы должны её проверить
            if ($this->_request->isPost()) {
                $formData = $this->_request->getPost();
 
                // проверяем форму
                if ($form->isValid($formData)) {
                     
                    // проверяем входные данные
                    $result = $this->_authenticate($form->getValue('realm'), $form->getValue('username'), $form->getValue('password'));
     
                    if ($result->isValid()) {
                        // запомним пользователя на 2 недели
                        if ($form->getValue('rememberMe')) {
                            Zend_Session::rememberMe(60*60*24*14);
                        }
                        // отправляем на главную
                        $this->_redirect('/');
                    } else {
                        // failure: выводим сообщение о ошибке
                        $this->view->error = 'Authorization error. Please check login or/and password';
                    }
                } else {
                    $form->populate($formData);
                }
            }
        } else {
            $this->view->login = true;
            $this->view->username = Zend_Auth::getInstance()->getIdentity();
        }
    }
     
    // генерация формы логина
    private function _getLoginForm()
    {
        $form = new Zend_Form();
        $form->setMethod('POST');
        $form->setName('userLoginForm');
 
        $username = new Zend_Form_Element_Text('username');
        $username->setLabel('User name')
                 ->setRequired(true)
                 ->addFilter('StripTags')
                 ->addFilter('StringTrim')
                 ->addValidator('Alnum')
                 ->addValidator('StringLength', false,
                                array(3,
                                      24));
 
        $password = new Zend_Form_Element_Password('password');
        $password->setLabel('Password')
                 ->setRequired(true)
                 ->setValue(null)
                 ->addValidator('StringLength', false,
                                array(6));
        $realm = new Zend_Form_Element_Select('realm');
        $realm->setLabel('Role')
              ->addMultiOptions(array('user'=>'User', 'admin'=>'Admin'))
              ->setRequired(true)
              ->setValue('user');
                                 
        $rememberMe = new Zend_Form_Element_Checkbox('rememberMe');
        $rememberMe->setLabel('Remember Me');
 
        $submit = new Zend_Form_Element_Submit('submit');
        $submit->setLabel('Login');
 
        $form->addElements(array($realm, $username, $password, $rememberMe, $submit));
 
        return $form;
    }
     
    // аутентификация - самая простая - используя Digest Adapter
    protected function _authenticate($realm, $login, $password)
    {
        $authAdapter = new Zend_Auth_Adapter_Digest(APPLICATION_PATH . '/configs/auth', $realm, $login, $password);
             
        $result = $authAdapter->authenticate();
         
        if ($result->isValid()) {
            // success: сохраняем роль пользователя в Zend_Auth
            Zend_Auth::getInstance()->getStorage()->write($authAdapter->getRealm());
        }
        return $result;
    }
     
    // разлогиниваемся
    public function logoutAction()
    {
        Zend_Auth::getInstance()->clearIdentity();
        $this->_redirect('/');
    }   
}

В комплекте добавим еще и view:

01
02
03
04
05
06
07
08
09
10
11
12
13
<div id="login">
<?php if ($this->login) :?>
    <h2>Username</h2>
    You are logged in as <strong class="username"><?php echo $this->username ?></strong>
<?php else : ?>
    <h2>Login</h2>
    <!-- выводим ошибку -->
    <?php if(!empty($this->error)) :?>
        <div id="error"><?php echo $this->escape($this->error);?></div>
    <?php endif; ?>
    <?php echo $this->form; ?>
<?php endif; ?>
</div>

Теперь необходимо написать тесты для этих контроллеров, но начну я с эмуляции авторизации в юнит-тестах – добавлю метод _doLogin в ControllerTestCase:

01
02
03
04
05
06
07
08
09
10
11
protected function _doLogin($realm, $login, $password)
{
    $authAdapter = new Zend_Auth_Adapter_Digest(APPLICATION_PATH . '/configs/auth', $realm, $login, $password);
         
    $result = $authAdapter->authenticate();
     
    if ($result->isValid()) {
        // success: сохраняем роль пользователя в Zend_Auth
        Zend_Auth::getInstance()->getStorage()->write($authAdapter->getRealm());
    }
}

Внимание! Для тестирования не следует использовать реальные данные, для данного примера лучше использовать либо тестовый файл аутентификации, либо создать mock для класса Zend_Auth

Теперь стоит проверить как мы логинимся/логаутимся:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class LoginControllerTest extends ControllerTestCase
{      
    // логинимся "правильным" данными
    public function testTrueUserLoginAction()
    {
        // эмулируем отправку формы
        $this->getRequest()
             ->setMethod('POST')
             ->setPost(array(  "realm" => "user",
                               "username" => "user",
                               "password" => "123456",
                               "rememberMe"=>1));
         
        $this->dispatch('/login/');
         
        // аутентификация должна пройти успешно, идентифицироваться мы должны как user
        $this->assertEquals(Zend_Auth::getInstance()->getIdentity(), 'user');
         
        // мы должны быть перенаправлены на главную страницу
        $this->assertRedirectTo('/');
    }
 
    // логинимся "неправильным" данными
    public function testFalseUserLoginAction()
    {
        $this->getRequest()
             ->setMethod('POST')
             ->setPost(array(  "realm" => "user",
                               "username" => "user",
                               "password" => "654321",
                               "rememberMe"=>0));
              
        $this->dispatch('/');
         
        // ищем в доме элемент с ID="error" и контентом 'Authorization error. Please check login or/and password'
        // лучше использовать assertQueryCount
        $this->assertQueryContentContains('#error', 'Authorization error. Please check login or/and password');
    }
 
     
    public function testLogoutAction()
    {
        // логинимся
        $this->_doLogin('admin', 'admin', '123456');
         
        // вызываем логаут
        $this->dispatch('/login/logout/');
         
        // теперь мы должны быть "забыты" Zend_Auth'ом
        $this->assertNull(Zend_Auth::getInstance()->getIdentity());
    }
}

Напишем еще один контроллер – Admin – с очень простой логикой – если заходит не админ – то его должно перенаправит на страницу denied:

01
02
03
04
05
06
07
08
09
10
11
class AdminController extends Zend_Controller_Action
{
    public function indexAction()
    {
        // проверяем пользователя на принадлежность к админам
        if (Zend_Auth::getInstance()->getIdentity() !== 'admin') {
            // если нет - то отправляем на страницу ошибки
            $this->_forward('denied','error');
        }
    }
}

Тесты тоже будут простенькими:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
class AdminControllerTest extends ControllerTestCase
{
    public function testIndexAction()
    {
        $this->dispatch('/admin/');
        $this->assertModule('default');
        $this->assertController('error');
        $this->assertAction('denied');
    }
 
    public function testIndexUnderAdminAction()
    {
        $this->_doLogin('admin', 'admin', '123456');
         
        $this->dispatch('/admin/');
        $this->assertModule('default');
        $this->assertController('admin');
        $this->assertAction('index');
    }
}

Результат:

1
2
3
4
PHPUnit 3.4.0beta3 by Sebastian Bergmann.
Time: 2 seconds
OK (13 tests, 39 assertions)
Generating code coverage report, this may take a moment.

Скачать

Вы можете скачать данный пример по ссылке ниже, в архиве нет Zend Framework’a, пример работает с версией 1.8.4, версия PHPUnit’a – 3.4.0b:

DownloadlessonPHPUnit + ZF

Ссылки

23 thoughts on “Юнит тестирование приложений на Zend Framework’е”

  1. Работаю с PHP более года и не сталкивался с PHPUnit, знал, что такое есть, что это полезная вещь, но работать к сожалению не доводилось. Спасибо за статью

  2. Хорошая статья ;) Как бот ответил, но она(статья) действительно интересная и актуальная %)
    зы: SyntaxHighlighter – спасибо, такая клёвая вещица, наверное удобнее пока не видел?

  3. pear install phpunit/PHPUnit

    На самом деле pear install -all phpunit/PHPUnit, так как по умолчанию он не тянет зависимости.

  4. C:\>cd “C:\Program Files\Zend\Apache2\htdocs\zf\tests”
    C:\Program Files\Zend\Apache2\htdocs\zf\tests>phpunit

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

    C:\>cd “C:\Program Files\Zend\Apache2\htdocs\zf\tests”
    C:\Program Files\Zend\Apache2\htdocs\zf\tests>phpunit ./

    Аналогичная ситуация. Возможно эту у меня косяки с php / phpunit, но:

    C:\>phpunit –version
    PHPUnit 3.3.17 by Sebastian Bergmann.

    C:\>php -v
    PHP 5.2.9 (cli) (built: May 26 2009 17:47:39)
    Copyright (c) 1997-2009 The PHP Group
    Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
    with Zend Extension Manager v5.1, Copyright (c) 2003-2009, by Zend Technologies
    with Zend Guard Loader v3.3, Copyright (c) 1998-2009, by Zend Technologies [loaded] [licensed] [enabled]
    with Zend Data Cache v4.0, Copyright (c) 2004-2009, by Zend Technologies [loaded] [licensed] [disabled]
    with Zend Utils v1.0, Copyright (c) 2004-2009, by Zend Technologies [loaded] [licensed] [enabled]
    with Zend Optimizer+ v4.0, Copyright (c) 1999-2009, by Zend Technologies [loaded] [licensed] [disabled]
    with Zend Debugger v5.2, Copyright (c) 1999-2009, by Zend Technologies [loaded] [licensed] [enabled]

    C:\>ver
    Microsoft Windows XP [Версия 5.1.2600]

    К тому же, то что паритачено в архиве там корневая директория – “zf”, в примере упоминается “zf-project”. Собственно ничего не работает. Сейчас под рукой нет другого набора тестов чтобы проверить на валидность конфигурацию системы, но пример вообще проверялся на валидность?

    1. Использовал PHPUnit 3.4b3 – на совместимость с 3.3 не проверял…

      Попробуй так:

      > phpunit . --configuration phpunit.xml
      

      Или даже используя полные пути:

      > phpunit "C:\Program Files\Zend\Apache2\htdocs\zf\tests" --configuration "C:\Program Files\Zend\Apache2\htdocs\zf\tests\phpunit.xml"
      

      Тесты проверялись на LAMP, вот мой репорт вживую: http://zf.dark.php.nixsolutions.com/tests/report/

      1. Если в текущей директории есть файл phpunit.xml, то все параметры можно опускать, phpunit будет ожидать их в xml. Скорее проблема каким-то образом тогда связана с моей текущей конфигурацией, так как до Zend Server CE делался WAPM, отдельной установкой каждого из компонентов, и уже всплывали проблемы из-за старых переменных окружения (PHP_* & PATH). На sf.net аналогичный пример запустился без особых сложностей, единственная проблема была связана с pear, и решилась созданием локальной (в дополнение к системной) установки pear и использование локального инсталлятора, так как PHPUnit требователен к версии PEAR.

      1. Не уверен что по этой причине, скорее всего из-за того что xDebug нужно грузить до Zend Extension Manger, нужно будет проверить в ближайшее время.

  5. Pingback: progg.ru
  6. Антон, здравствуйте,

    а вы не в курсе как можно потестировать значение в поле ввода?

    Например:

    Что в этом случае использовать? Или как-то настроить assertQueryContentContains?

    Заранее спасибо за разъяснения.

  7. в предыдущем посте где например было
    html
    input type=”text” name=”test” id=”test” value=”1″ /
    html

    с угловыми скобками

  8. Полезный пост, спасибо! Раньше не использовал файл конфигурации тестов в PHPUnit. Подскажите, а есть ли возможность запускать одиночные тесты при использовании глобального файла конфигурации?

    1. В phpdoc классе теста пишешь

      /**
      * @group mysingletest
      */
      class ….Test….

      а запускаешь через phpunit –group mysingletest

  9. Привет. Заметил, что у тебя в ручной настройке PHPUnit-a написано менять файл PHPUnit/Util/Fileloader.php, а на официальном сайте написано другое

    ———-
    3. Prepare the PHPUnit/Util/PHP.php script:

    a. Replace the @php_bin@ string in it with the path to your PHP command-line interpreter (usually /usr/bin/php).
    ———-

    Что скажешь?

  10. Может вы сможете помочь. Пытаюсь запустить тест, но выкидывает ошибку. В чём может быть проблема?

    Fatal error: Uncaught exception ‘PHPUnit_Framework_Exception’ with message ‘Could not load “/mnt/hgfs/www/project/tests/phpunit.xml”.’ in /usr/share/php/PHPUnit/Util/XML.php:216
    Stack trace:
    #0 /usr/share/php/PHPUnit/Util/XML.php(166): PHPUnit_Util_XML::load(‘?__construct(‘/mnt/hgfs/www/j…’)
    #3 /usr/share/php/PHPUnit/TextUI/Command.php(753): PHPUnit_Util_Configuration::getInstance(‘/mnt/hgfs/www/j…’)
    #4 /usr/share/php/PHPUnit/TextUI/Command.php(155): PHPUnit_TextUI_Command->handleArguments(Array)
    #5 /usr/share/php/PHPUnit/TextUI/Command.php(146): PHPUnit_TextUI_Command->run(Array, true)
    #6 /usr/bin/phpunit(54): PHPUnit_TextUI_Command::main()
    #7 {main}
    thrown in /usr/share/php/PHPUnit/Util/XML.php on line 216

    1. Как решил эту проблему? С файлом “phpunit.xml”:

      Fatal error: Uncaught exception ‘PHPUnit_Framework_Exception’ with message ‘Could not load “/mnt/hgfs/www/project/tests/phpunit.xml”.’ in /usr/share/php/PHPUnit/Util/XML.php:216

  11. Такое бывает, если phpunit.xml в виндовой кодировке.

  12. Сделала все как написано.. вся иерархия папок.. файлов и их содержимого… но когда набираю в консоле в папке \tests phpunit – получаю ошибку – Could not open include file: .\pear\PHPUnit2\TextUI\TestRunner.php… Подскажите как решить эту проблему, пожайлуста

    1. Выполни в консоле:

      phpunit –version

      Путь “.\pear\PHPUnit2\TextUI\TestRunner.php” выглядит дико при условии что PHPUnit уже 3.5.10.

  13. Установка через pear сработала только с такой последовательностью:

    pear channel-update pear.php.net
    pear upgrade pear
    pear channel-discover pear.phpunit.de
    pear channel-discover components.ez.no
    pear channel-discover pear.symfony-project.com
    pear install phpunit/PHPUnit

Comments are closed.