Что нам нужно для запуска тестов

  1. Composer.
  2. Библиотеки PHPUnit и PHPUnit-Selenium. Это мы поставим через composer + некоторые дополнительные библиотеки
  3. Сам сервер Selenium
  4. Драйвер google chrome
  5. Переопределить два класса для тестов
  6. Новый проект yii1

Начнем.

Описание процесса установки будет происходить для ОС ubuntu.
Надеюсь, у вас стоит composer поэтому, не будет на этом останавливаться.
Также, у вас должен быть установлен новый проект yii1

Устанавливаем PHPUnit

Я устанавливаю в глобальный репозиторий composer.

Записываем в файл composer.json в раздел require

"require": {
    "phpunit/phpunit": "^5.5",
    "phpunit/php-invoker": "^1.1",
    "phpunit/dbunit": "^2.0",
    "phpunit/phpunit-selenium": "^3.0",
    "phpunit/phpunit-story": "^1.0"
}

и выполняем composer update.

Устанавливаем сервер Selenium

Selenium нужен для того, чтобы при помощи phpunit открыть браузер и чего-то в нем делать (искать элементы, нажимать на кнопку и т.д.)

Заходим на сайте http://www.seleniumhq.org/download/. Ищем секцию Selenium Standalone Server, нажимаем на ссылку после текста "Download version". Должен скачаться файл selenium-standalone-...jar.

Для себя, я его переименовал в selenuim.jar

Запускаем selenum сервер.

$java -jar selenium.jar

Webdriver Google Chrome.

У меня не получилось запустить тесты в firefox (буду разбираться. потом отпишусь).

Заходим на страницу https://sites.google.com/a/chromium.org/chromedriv... и качаем архив. Распаковываем архив и переносим файл chromedriver в папку /usr/bin


Переопределяем стандартные классы Yii1

Нам нужно переопределить классы CWebTestCase и CTestCase.

Зачем это нужно. Дело в том, что в этих классах определена попытка загрузить PHPUnit старой версии который, добавлялся через pear. Также, в этих классах определяется автолоадер для PHPUnit старой версии.

В каталоге protected/tests создаем класс MyWebTestCase и переносим в него функционал класса CWebTestCase.

Ок.Теперь, нам нужно установить автолоадер composer-а.

Над описанием класса MyWebTestCase пишем такой код:

spl_autoload_unregister(array('YiiBase','autoload'));
require_once('/home/some-user/vendor/autoload.php'); // Тут нужно указать путь к вашей папке vendor
spl_autoload_register(array('YiiBase','autoload'));
Yii::import('system.test.CTestCase');

В итоге, должо получаться что-то вроде

// Переопределяем автолоадер для загрузчика composer
spl_autoload_unregister(array('YiiBase','autoload'));
require_once('/home/kot/vendor/autoload.php');
spl_autoload_register(array('YiiBase','autoload'));
Yii::import('system.test.CTestCase');

class MyWebTestCase extends PHPUnit_Extensions_Selenium2TestCase
{

    /**
     * @var array a list of fixtures that should be loaded before each test method executes.
     * The array keys are fixture names, and the array values are either AR class names
     * or table names. If table names, they must begin with a colon character (e.g. 'Post'
     * means an AR class, while ':Post' means a table name).
     * Defaults to false, meaning fixtures will not be used at all.
     */
    protected $fixtures=false;

    /**
     * PHP magic method.
     * This method is overridden so that named fixture data can be accessed like a normal property.
     * @param string $name the property name
     * @throws Exception if unknown property is used
     * @return mixed the property value
     */
    public function __get($name)
    {
        if(is_array($this->fixtures) && ($rows=$this->getFixtureManager()->getRows($name))!==false)
            return $rows;
        else
            throw new Exception("Unknown property '$name' for class '".get_class($this)."'.");
    }

    /**
     * PHP magic method.
     * This method is overridden so that named fixture ActiveRecord instances can be accessed in terms of a method call.
     * @param string $name method name
     * @param string $params method parameters
     * @return mixed the property value
     */
    public function __call($name,$params)
    {
        if(is_array($this->fixtures) && isset($params[0]) && ($record=$this->getFixtureManager()->getRecord($name,$params[0]))!==false)
            return $record;
        else
            return parent::__call($name,$params);
    }

    /**
     * @return CDbFixtureManager the database fixture manager
     */
    public function getFixtureManager()
    {
        return Yii::app()->getComponent('fixture');
    }

    /**
     * @param string $name the fixture name (the key value in {@link fixtures}).
     * @return array the named fixture data
     */
    public function getFixtureData($name)
    {
        return $this->getFixtureManager()->getRows($name);
    }

    /**
     * @param string $name the fixture name (the key value in {@link fixtures}).
     * @param string $alias the alias of the fixture data row
     * @return CActiveRecord the ActiveRecord instance corresponding to the specified alias in the named fixture.
     * False is returned if there is no such fixture or the record cannot be found.
     */
    public function getFixtureRecord($name,$alias)
    {
        return $this->getFixtureManager()->getRecord($name,$alias);
    }

    /**
     * Sets up the fixture before executing a test method.
     * If you override this method, make sure the parent implementation is invoked.
     * Otherwise, the database fixtures will not be managed properly.
     */
    protected function setUp()
    {
        parent::setUp();
        if(is_array($this->fixtures))
            $this->getFixtureManager()->load($this->fixtures);
    }

}

Открываем класс TestCase и делаем тоже самое.

// Переопределяем автолоадер для загрузчика composer
spl_autoload_unregister(array('YiiBase','autoload'));
require_once('/home/kot/vendor/autoload.php');
spl_autoload_register(array('YiiBase','autoload'));
abstract class MyTestCase extends PHPUnit_Framework_TestCase
{
}

Переопределяем тесты их коробки.

Дело в том, что selenium и selenium2 отличаются (хорошая статья на хабре https://habrahabr.ru/sandbox/59007/). Поэтому, нам нужно немного изменить функционал тестов.

Открываем файл protected/tests/functional/SiteTest.php:

class SiteTest extends WebTestCase
{

    public function testIndex()
    {
        $this->url('');  // в selenium 1 это была фукция open
        $this->timeouts()->implicitWait(3000); //подождем, полюбуемся результатом
        $this->byLinkText('Welcome');
    }

    public function testContact()
    {
        $this->url('site/contact'); // в selenium 1 это была фукция open
        $this->timeouts()->implicitWait(3000); //подождем, полюбуемся результатом
        $this->byLinkText('Contact Us');
        $this->assertElementPresent('name=ContactForm[name]');
        $this->type('name=ContactForm[name]','tester');
        $this->type('name=ContactForm[email]','tester@example.com');
        $this->type('name=ContactForm[subject]','test subject');
        $this->click("//input[@value='Submit']");
        $this->waitForTextPresent('Body cannot be blank.');
    }

    // Эту функцию я закомментил. Заменить старый функционал на новый, я предалгаю самостоятельно        
    /*
    public function testLoginLogout()
    {
        $this->url('/site/logout');
        $this->timeouts()->implicitWait(3000);
        // ensure the user is logged out
        if($this->byLinkText('Logout'))
            $this->clickAndWait('link=Logout (demo)');
        // test login process, including validation
        $this->clickAndWait('link=Login');
        $this->assertElementPresent('name=LoginForm[username]');
        $this->type('name=LoginForm[username]','demo');
        $this->click("//input[@value='Login']");
        $this->waitForTextPresent('Password cannot be blank.');
        $this->type('name=LoginForm[password]','demo');
        $this->clickAndWait("//input[@value='Login']");
        $this->assertTextNotPresent('Password cannot be blank.');
        $this->assertTextPresent('Logout');
        // test logout process
        $this->assertTextNotPresent('Login');
        $this->clickAndWait('link=Logout (demo)');
        $this->assertTextPresent('Login');
    } */

}

Теперь:

  1. открываем файл protected/tests/phpunit.xml и убираем теги описывающие браузер
  2. открываем файл protected/tests/WebTestCase.php меняем:

/** * Change the following URL based on your server configuration * Make sure the URL ends with a slash so that we can use relative URLs in test cases */ /** * The base class for functional test cases. * In this class, we set the base URL for the test application. * We also provide some common methods to be used by concrete test classes. */ // указываете свой url к сайтую. index-test.php - обязательно define('TEST_BASE_URL','http://yii1/index-test.php'); //Меняем родительский класс с CWebTestCase на MyWebTestCase class WebTestCase extends MyWebTestCase { /** * Sets up before each test method runs. * This mainly sets the base URL for the test application. */ protected function setUp() { parent::setUp(); $this->setBrowser('chrome'); $this->setBrowserUrl(TEST_BASE_URL); } }

3. в консоле заходим в папку protected/tests и выполняем команду $ phpunit functional/SiteTest.php

В результате, должны открыться окна chrom-а с вашим проектом.