Продвинутое использование

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

Интерактивная консоль

Интерактивная консоль добавлена для опробования команд Codeception перед тем, как они будут выполнены внутри тестов. Данная возможность была анонсирована начиная с версии 1.6.0.

console

Вы можете запустить консоль с помощью команды:

php codecept.phar console suitename

Теперь Вы можете выполнять любые команды соответствующего Guy-класса и сразу же видеть результаты их выполнения. Это особенно полезно в случае работы с модулями Selenium. Запуск Selenium и браузера для тестирования обычно занимает довольно продолжительное время. Однако при использовании консоли Вы можете попробовать разнообразные селекторы и команды, после чего сможете быть уверенны в том, что написанный Вами тест выполнится.

Полезный совет: покажите начальству как резво Вы манипулируете веб страницами с помощью консоли и Selenium. Вы сможете убедить его в том, что довольно просто автоматизировать подобные вещи и начать использовать приемочное тестирование в проекте.

Запуск из разных каталогов

Если у Вас есть несколько проектов, содержащих Coeception тесты, Вы можете использовать один codecept.phar файл для их запуска. Чтобы запускать Codeception из других директорий, добавляйте опцию -c к любой Codeception команде кроме bootstrap.

php codecept.phar run -c ~/projects/ecommerce/
php codecept.phar run -c ~/projects/drupal/
php codecept.phar generate:cept acceptance CreateArticle -c ~/projects/drupal/

Для создания проекта в директории отличной от той, где Вы находитесь, просто добавьте ее путь как параметр:

php codecept.phar bootstrap ~/projects/drupal/

В сущности, опция -c позволяет указать не только путь, но и файл конфигурации. Таким образом у вас может быть несколько различных файлов codeception.yml в одном тестовом наборе. Вы можете использовать их для указания разных переменных окружения и настроек. Просто передайте имя конфигурационного файла в параметре -c для того, чтобы выполнить тесты с настройками, указанными в данном конфигурационном файле.

Группы

Есть несколько путей позволяющих выполнить группу тестов. Вы можете выполнить тесты в определенной директории:

php codecept.phar run tests/acceptance/admin

Или выполнить одну (или несколько) групп тестов:

php codecept.phar run -g admin -g editor

В данном случае будут выполнены все тесты принадлежащие группам admin или editor. Концепция групп взята из PHPUnit и его классических тестов, которые ведут себя подобным образом. Чтобы добавить Cept тест к группе, используйте переменную $scenario:

<?php
$scenario->group('admin');
$scenario->group('editor');
// or
$scenario->group(array('admin', 'editor'))
// or
$scenario->groups(array('admin', 'editor'))

$I = new WebGuy($scenario);
$I->wantToTest('admin area');
?>

Чтобы добавить тест к группе классических или Cests тестов, можно использовать аннотацию @group:

<?php
/**
 * @group admin
 */
public function testAdminUser()
{
    $this->assertEquals('admin', User::find(1)->role);
}
?>

Та же аннотация может быть использована в Cest классах.

Cest Классы

В случае, если Вы хотите получить class-like структуру ваших Cept тестов, вместо использования простого PHP, Вы можете использовать Cest формат. Это очень просто и полностью совместимо с Cept сценариями. Если Вы считаете, что Ваши тесты стали достаточно длинными и Вы хотите разбить их на части, Вы можете поместить их внутрь класса.

Для генерации Cest файла, воспользуйтесь следующей командой:

php codecept.phar generate:cest suitename CestName

Это сгенерирует файл похожий на этот:

<?php
class BasicCest
{

    public function _before()
    {
    }

    public function _after()
    {
    }

    // tests
    public function tryToTest(\WebGuy $I) {

    }
}
?>

Каждый публичный метод Cest класса (кроме начинающихся с _) будет выполнен как тест, куда первым параметром будет передан Guy-класс, а вторым параметром будет передана переменная $scenario.

В методах _before и _after можно указывать разнообразные настройки, которые будут выполняться до и после тестов данного класса. Это делает Cest тесты более гибкими, чем Cepts тесты, которые основываются только на похожих методах в Helper классах.

Как Вы могли видеть выше, мы передаем класс Guy в метод tryToTest. Это позволяет писать сценарии тестирования точно так же, как мы делали это ранее.

<?php
class BasicCest
{
    // test
    public function checkLogin(\WebGuy $I) {
        $I->wantTo('log in to site');
        $I->amOnPage('/');
        $I->click('Login');
        $I->fillField('username', 'jon');
        $I->fillField('password','coltrane');
        $I->click('Enter');
        $I->see('Hello, Jon');
        $I->seeInCurrentUrl('/account');
    }
}
?>

Стоит отметить, что при использовании Cest файлов появляются некоторые ограничения. Вы не сможете работать с _bootstrap.php так как Вы делали это в Cept тестах. Иногда удобно хранить некоторые переменные, которые должны быть переданы тесту в bootstrap файлах. В файлах Cest Вам придется включать все внешние переменные вручную, с помощью глобальных или статических переменных.

В качестве обходного пути можно использовать классы фикстур Fixtures, которые являются, по сути, глобальным хранилищем переменных. Можно передать любые данные из _bootstrap.php или любого другого места с помощью вызова Fixtures::add(). Вы можете использовать в классах Cest методы _before и _after для загрузки фикстур в начале теста и их удаления после его выполнения, что так же довольно удобно.

Как Вы могли заметить, классы Cest не имеют родителя, как, к примеру, \Codeception\TestCase\Test или PHPUnit_Framework_TestCase. Это сделано нарочно. Это позволяет Вам расширять данные классы путем создания общего класса родителя. В данном классе Вы можете описать общие поведения и методы, которые в дальнейшем могут быть использованы в унаследованных классах.

При этом не забудьте установить для таких методов модификатор protected, иначе они будут выполнены как тесты.

В дополнение, Вы можете определить метод _failed в классах Cest, который будет вызван в случае, если в тесте произошла ошибка error или он 'провалился'.

Аннотации

добавлено начиная с версии 1.7.0

Вы можете управлять Cest файлами с помощью аннотаций. Вы можете использовать аннотацию @guy для передачи Guy-класса отличного от того, что установлен в конфигурации. Это довольно удобно, если Вы хотите передать StepObject здесь (смотрите ниже).

<?php
/**
 * @guy WebGuy\AdminSteps
 */
class AdminCest {

    function banUser(WebGuy\AdminSteps $I)
    {
        // ...
    }

}
?>

Аннотация может быть добавлена к методу в doc-блоке блоке.

Вы можете контролировать порядок выполнения используя аннотации @before и @after, а также переместить некоторые действия в protected (не тестируемые) методы и вызвать их до или после тестового метода, добавляя их в аннотации.

<?php
class ModeratorCest {

    protected function login(WebGuy $I)
    {
        $I->amOnPage('/login');
        $I->fillField('Username', 'miles');
        $I->fillField('Password', 'davis');
        $I->click('Login');
    }

    /**
     * @before login
     */
    function banUser(WebGuy $I)
    {
        $I->amOnPage('/users/charlie-parker');
        $I->see('Ban', '.button');
        $I->click('Ban');        
    }
}
?>

Вы так же можете использовать @before и @after для подключаемых функций. Однако, нельзя иметь несколько аннотаций в одном методе.

Рефакторинг

Во время роста базы тестов может потребоваться их рефакторинг, возможно, понадобится выделить некоторые общие поведения и методы. Классический пример — действие login, которое возможно будет вызываться практически в каждом тесте из тестового набора. Мудрое решение — написать данное действие однажды и использовать его во всех тестах, где это необходимо.

Не забывайте принцип DRY :)

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

<?php class TestCommons 
{
    public static $username = 'jon';
    public static $password = 'coltrane';

    public static logMeIn($I)
    {
        $I->amOnPage('/login');
        $I->fillField('username', 'jon');
        $I->fillField('password','coltrane');
        $I->click('Enter');
    }
}
?>

Этот файл затем может быть подключен в файл _bootstrap.php

<?php
// bootstrap
require_once '/path/to/test/commons/TestCommons.php';
?>

и затем может быть использован в Ваших сценариях:

<?php
$I = new WebGuy($scenario);
TestCommons::logMeIn($I);
?>

Теперь идея должна быть Вам понятна. Codeception не обеспечивает единой стратегии при управлении тестами. Однако он достаточно гибок и позволяет создавать любые необходимые классы, которые могут понадобиться Вам во время тестирования. Используя похожий подход, Вы можете реализовать паттерны PageObject и StepObject.

PageObject и StepObjects

В следующих версиях Codeception будет использовать PageObjects и StepObjects из коробки. Однако сейчас Вы можете попробовать реализовать ваши собственные версии данных объектов. У нас есть пара отличных статей на данную тему, обратившись к которым Вы сможете разобраться в том, что же такое PageObjects, почему Вам может быть полезно их использовать и как они могут быть реализованы.

Заключение

Codeception — фреймворк, который на первый взгляд выглядит довольно просто. Однако он позволяет создавать достаточно мощные тесты, имеющие единый API, рефакторить их и писать тесты быстрее используя интерактивную консоль. Тесты Codeception легко могут быть организованны в группы или в классы Cest. Вероятно, это достаточно большой функционал для одного фреймворка. Не смотря на это, Codeception следует принципу KISS: его просто изучить, просто использовать, просто расширять.