Spec-Zone.ru › Codeception

Расширенное использование

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

Классы Cest

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

Вы можете создать файл Cest, выполнив команду:

php vendor/bin/codecept generate:cest suitename CestName

Сгенерированный файл будет выглядеть так:

<?php
class BasicCest
{
    public function _before(\AcceptanceTester $I)
    {
    }

    public function _after(\AcceptanceTester $I)
    {
    }

    // tests
    public function tryToTest(\AcceptanceTester $I)
    {
    }
}

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

В методах _before и _after вы можете использовать общие настройки и завершения для тестов в классе.

Как видите, мы передаём объект Actor в метод tryToTest. Это позволяет нам писать сценарии так же, как мы делали раньше:

<?php
class BasicCest
{
    // test
    public function tryToTest(\AcceptanceTester $I)
    {
        $I->amOnPage('/');
        $I->click('Login');
        $I->fillField('username', 'john');
        $I->fillField('password', 'coltrane');
        $I->click('Enter');
        $I->see('Hello, John');
        $I->seeInCurrentUrl('/account');
    }
}

Как видите, классы Cest не имеют родителей. Это сделано намеренно. Это позволяет вам расширять свои классы общим поведением и обходными путями, которые могут использоваться в дочерних классах. Но не забудьте сделать эти методы protected, чтобы они не выполнялись как тесты.

Формат Cest также может содержать хуки, основанные на результатах тестов:

  • _failed будет выполняться при неудачном тесте
  • _passed будет выполняться при успешном тесте
<?php
public function _failed(\AcceptanceTester $I)
{
    // will be executed on test failure
}

public function _passed(\AcceptanceTester $I)
{
    // will be executed when test is successful
}

Инъекция зависимостей

Codeception поддерживает простую инъекцию зависимостей для классов Cest и \Codeception\TestCase\Test. Это означает, что вы можете указать, какие классы вам нужны в качестве параметров специального метода _inject(), и Codeception автоматически создаст соответствующие объекты и вызовет этот метод, передавая все зависимости в качестве аргументов. Это может быть полезно при работе с помощниками. Вот пример для Cest:

<?php
class SignUpCest
{
    /**
     * @var Helper\SignUp
     */
    protected $signUp;

    /**
     * @var Helper\NavBarHelper
     */
    protected $navBar;

    protected function _inject(\Helper\SignUp $signUp, \Helper\NavBar $navBar)
    {
        $this->signUp = $signUp;
        $this->navBar = $navBar;
    }

    public function signUp(\AcceptanceTester $I)
    {
        $this->navBar->click('Sign up');
        $this->signUp->register([
            'first_name'            => 'Joe',
            'last_name'             => 'Jones',
            'email'                 => 'joe@jones.com',
            'password'              => '1234',
            'password_confirmation' => '1234'
        ]);
    }
}

И для классов Test:

<?php
class MathTest extends \Codeception\TestCase\Test
{
   /**
    * @var \UnitTester
    */
    protected $tester;

    /**
     * @var Helper\Math
     */
    protected $math;

    protected function _inject(\Helper\Math $math)
    {
        $this->math = $math;
    }

    public function testAll()
    {
        $this->assertEquals(3, $this->math->add(1, 2));
        $this->assertEquals(1, $this->math->subtract(3, 2));
    }
}

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

Для работы автоподстановки вам необходимо реализовать метод _inject() со списком желаемых аргументов. Важно указать тип аргументов, чтобы Codeception мог угадать, какие объекты ожидается получить. Метод _inject() будет вызываться только один раз, сразу после создания объекта TestCase (либо Cest, либо Test). Инъекция зависимостей также будет работать аналогичным образом для классов Helper и Actor.

Каждый тест класса Cest может объявлять свои зависимости и получать их из аргументов метода:

<?php
class UserCest
{
    function updateUser(\Helper\User $u, \AcceptanceTester $I, \Page\User $userPage)
    {
        $user = $u->createDummyUser();
        $userPage->login($user->getName(), $user->getPassword());
        $userPage->updateProfile(['name' => 'Bill']);
        $I->see('Profile was saved');
        $I->see('Profile of Bill','h1');
    }
}

Более того, Codeception может рекурсивно разрешать зависимости (когда A зависит от B, а B зависит от C и т. д.) и обрабатывать параметры примитивных типов со значениями по умолчанию (например, $param = 'default'). Конечно, вам не разрешается иметь циклические зависимости.

Пример аннотации

Что если вы хотите выполнить один и тот же сценарий теста с разными данными? В этом случае вы можете инжектировать примеры как экземпляры \Codeception\Example. Данные определяются с помощью аннотации @example, используя JSON или нотацию в стиле Doctrine (ограниченную одной строкой). Стиль Doctrine:

<?php
class EndpointCest
{
 /**
  * @example ["/api/", 200]
  * @example ["/api/protected", 401]
  * @example ["/api/not-found-url", 404]
  * @example ["/api/faulty", 500]
  */
  public function checkEndpoints(ApiTester $I, \Codeception\Example $example)
  {
    $I->sendGet($example[0]);
    $I->seeResponseCodeIs($example[1]);
  }
}

JSON:

<?php
class PageCest
{
 /**
  * @example { "url": "/", "title": "Welcome" }
  * @example { "url": "/info", "title": "Info" }
  * @example { "url": "/about", "title": "About Us" }
  * @example { "url": "/contact", "title": "Contact Us" }
  */
  public function staticPages(AcceptanceTester $I, \Codeception\Example $example)
  {
    $I->amOnPage($example['url']);
    $I->see($example['title'], 'h1');
    $I->seeInTitle($example['title']);
  }
}
Если вы используете JSON-нотацию, имейте в виду, что все строковые ключи и значения должны быть заключены в двойные кавычки (`"`) в соответствии со стандартом JSON.

Данные в формате ключ-значение в синтаксисе аннотации в стиле Doctrine:

<?php
class PageCest
{
 /**
  * @example(url="/", title="Welcome")
  * @example(url="/info", title="Info")
  * @example(url="/about", title="About Us")
  * @example(url="/contact", title="Contact Us")
  */
  public function staticPages(AcceptanceTester $I, \Codeception\Example $example)
  {
    $I->amOnPage($example['url']);
    $I->see($example['title'], 'h1');
    $I->seeInTitle($example['title']);
  }
}

Аннотации DataProvider

Вы также можете использовать аннотацию @dataProvider для создания динамических примеров для классов Cest, используя защищённый метод для предоставления данных примера:

<?php
class PageCest
{
   /**
    * @dataProvider pageProvider
    */
    public function staticPages(AcceptanceTester $I, \Codeception\Example $example)
    {
        $I->amOnPage($example['url']);
        $I->see($example['title'], 'h1');
        $I->seeInTitle($example['title']);
    }

    /**
     * @return array
     */
    protected function pageProvider() // alternatively, if you want the function to be public, be sure to prefix it with `_`
    {
        return [
            ['url'=>"/", 'title'=>"Welcome"],
            ['url'=>"/info", 'title'=>"Info"],
            ['url'=>"/about", 'title'=>"About Us"],
            ['url'=>"/contact", 'title'=>"Contact Us"]
        ];
    }
}

Аннотация @dataprovider также доступна для юнит-тестов, в этом случае метод поставщика данных должен быть публичным. Для получения дополнительной информации о том, как использовать поставщик данных для юнит-тестов, обратитесь к документации PHPUnit.

Аннотации Before/After

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

<?php
class ModeratorCest {

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

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

    /**
     * @before login
     * @before cleanup
     * @after logout
     * @after close
     */
    public function addUser(AcceptanceTester $I)
    {
        $I->amOnPage('/users/charlie-parker');
        $I->see('Ban', '.button');
        $I->click('Ban');
    }
}

Среды

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

Давайте продемонстрируем использование сред для случая с браузерами.

Нам нужно добавить несколько новых строк в acceptance.suite.yml:

actor: AcceptanceTester
modules:
    enabled:
        - WebDriver
        - \Helper\Acceptance
    config:
        WebDriver:
            url: 'http://127.0.0.1:8000/'
            browser: 'firefox'
env:
    chrome:
         modules:
            config:
                WebDriver:
                    browser: 'chrome'

    firefox:
        # nothing changed

В основном вы можете определить разные среды внутри корневого файла env, назвать их (chrome, firefox и т. д.), а затем переопределить любые параметры конфигурации, которые были установлены ранее.

Вы также можете определить среды в отдельных конфигурационных файлах, размещённых в каталоге, указанном опцией envs в конфигурации paths:

paths:
    envs: tests/_envs

Имена этих файлов используются в качестве имён сред (например, chrome.yml или chrome.dist.yml для среды, названной chrome). Вы можете сгенерировать новый файл с этой конфигурацией среды, используя команду generate:environment:

$ php vendor/bin/codecept g:env chrome

В этом файле вы можете указать только те параметры, которые вы хотите переопределить:

modules:
    config:
        WebDriver:
            browser: 'chrome'

Конфигурационные файлы среды объединяются в главную конфигурацию перед объединением конфигурации набора тестов.

Вы легко можете переключаться между этими конфигурациями, выполняя тесты с опцией --env. Чтобы запустить тесты только для Firefox, вам нужно передать --env firefox как опцию:

$ php vendor/bin/codecept run acceptance --env firefox

Чтобы запустить тесты во всех браузерах, перечислите все среды:

$ php vendor/bin/codecept run acceptance --env chrome --env firefox

Тесты будут выполняться 3 раза, каждый раз в другом браузере.

Также возможно объединить несколько сред в одну конфигурацию, разделив их запятой:

$ php vendor/bin/codecept run acceptance --env dev,firefox --env dev,chrome --env dev,firefox

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

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

Требуемые среды можно указать с помощью аннотации @env для тестов в форматах Test и Cest:

<?php
class UserCest
{
    /**
     * This test will be executed only in 'firefox' and 'chrome' environments
     *
     * @env firefox
     * @env chrome
     */
    public function webkitOnlyTest(AcceptanceTester $I)
    {
        // I do something
    }
}

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

Получение метаданных сценария

Иногда вам может потребоваться изменить поведение теста в реальном времени. Например, поведение одного и того же теста может отличаться в Firefox и в Chrome. Во время выполнения мы можем получить имя текущей среды, имя теста или список включённых модулей, вызвав метод $scenario->current().

<?php
// retrieve current environment
$scenario->current('env');

// list of all enabled modules
$scenario->current('modules');

// test name
$scenario->current('name');

// browser name (if WebDriver module enabled)
$scenario->current('browser');

// capabilities (if WebDriver module enabled)
$scenario->current('capabilities');

Вы можете инжектировать \Codeception\Scenario следующим образом:

<?php
public function myTest(\AcceptanceTester $I, \Codeception\Scenario $scenario)
{
    if ($scenario->current('browser') == 'chrome') {
      // ...
    }
}

Codeception\Scenario также доступен в классах Actor и StepObjects. Вы можете получить к нему доступ с помощью $this->getScenario().

Перемешивание

По умолчанию Codeception выполняет тесты в алфавитном порядке. Чтобы убедиться, что тесты не зависят друг от друга (если не объявлены явно через @depends), вы можете включить опцию shuffle.

# inside codeception.yml
settings:
    shuffle: true

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

codecept run -o "settings: shuffle: true"

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

$ codecept run 
Codeception PHP Testing Framework v2.4.5
Powered by PHPUnit 5.7.27 by Sebastian Bergmann and contributors.
[Seed] 1872290562

Передайте скопированное семя в опцию --seed:

codecept run --seed 1872290562

Зависимости

С помощью аннотации @depends вы можете указать тест, который должен быть пройден перед текущим. Если этот тест завершится неудачно, текущий тест будет пропущен. Вы должны передать имя метода теста, от которого вы зависите.

<?php
class ModeratorCest {

    public function login(AcceptanceTester $I)
    {
        // logs moderator in
    }

    /**
     * @depends login
     */
    public function banUser(AcceptanceTester $I)
    {
        // bans user
    }
}

@depends применяется к форматам Cest и Codeception\Test\Unit. Зависимости могут быть установлены между разными классами. Чтобы указать зависимый тест из другого файла, вы должны предоставить подпись теста. Обычно подпись теста соответствует формату className:methodName. Но чтобы получить точную подпись теста, просто запустите тест с опцией --steps , чтобы увидеть её:

Signature: ModeratorCest:login`

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

Запуск из разных папок

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

$ php vendor/bin/codecept run -c ~/projects/ecommerce/
$ php vendor/bin/codecept run -c ~/projects/drupal/
$ php vendor/bin/codecept generate:cest acceptance CreateArticle -c ~/projects/drupal/

Чтобы создать проект в директории, отличной от текущей, просто укажите его путь в качестве параметра:

$ php vendor/bin/codecept bootstrap ~/projects/drupal/

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

Группы

Есть несколько способов выполнить группу тестов. Вы можете запускать тесты из определённой директории:

$ php vendor/bin/codecept run tests/acceptance/admin

Вы можете выполнить одну (или несколько) конкретных групп тестов:

$ php vendor/bin/codecept run -g admin -g editor

Концепция групп была взята из PHPUnit и работает аналогичным образом.

Для файлов Test и Cest вы можете использовать аннотацию @group для добавления теста в группу.

<?php
/**
 * @group admin
 */
public function testAdminUser()
{
}

Для файлов .feature (Gherkin) используйте теги:

@admin @editor
Feature: Admin area

Файлы групп

Группы могут быть определены в глобальных или конфигурационных файлах набора тестов. Тесты для групп могут быть указаны как массив имён файлов или директорий, содержащих их:

groups:
  # add 2 tests to db group
  db: [tests/unit/PersistTest.php, tests/unit/DataTest.php]

  # add all tests from a directory to api group
  api: [tests/functional/api]

Список тестов для группы может быть передан из файла группы. Он должен быть определён в текстовом формате со именами тестов на отдельных строках:

tests/unit/DbTest.php
tests/unit/UserTest.php:create
tests/unit/UserTest.php:update

Файл группы можно включить по его относительному имени файла:

groups:
  # requiring a group file
  slow: tests/_data/slow.txt

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

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

groups:
  p*: tests/_data/p*

Это загрузит все найденные p* файлы в tests/_data как группы. Имена групп будут следующими: p1, p2, ..., pN.

Форматы

В дополнение к стандартным форматам тестов (Cest, Unit, Gherkin) вы можете реализовать свои собственные классы форматов для настройки выполнения тестов. Укажите их в конфигурации вашей сборки:

formats:
  - \My\Namespace\MyFormat

Затем определите класс, который реализует интерфейс LoaderInterface

namespace My\Namespace;

class MyFormat implements \Codeception\Test\Loader\LoaderInterface
{
    protected $tests;
    
    protected $settings;
    
    public function __construct($settings = [])
    {
        //These are the suite settings
        $this->settings = $settings;
    }
    
    public function loadTests($filename)
    {
        //Load file and create tests
    }

    public function getTests()
    {
        return $this->tests;
    }

    public function getPattern()
    {
        return '~Myformat\.php$~';
    }
}

Автозаполнение оболочки

Для оболочек bash и zsh вы можете использовать автозаполнение для своих проектов Codeception, выполнив следующее в вашей оболочке (или добавьте его в свой .bashrc/.zshrc):

# BASH ~4.x, ZSH
source <([codecept location] _completion --generate-hook --program codecept --use-vendor-bin)

# BASH ~3.x, ZSH
[codecept location] _completion --generate-hook --program codecept --use-vendor-bin | source /dev/stdin

# BASH (any version)
eval $([codecept location] _completion --generate-hook --program codecept --use-vendor-bin)

Описание

Используя приведенный выше код в вашей оболочке, Codeception будет пытаться выполнить автозаполнение следующего:

  • Команды
  • Наборы тестов
  • Пути к тестам

Использование -use-vendor-bin является необязательным. Этот параметр будет работать для большинства проектов Codeception, где Codeception находится в вашей папке vendor/bin. Но в случае использования глобальной установки Codeception, например, этот параметр не используется.

Обратите внимание, что с параметром -use-vendor-bin, ваши команды будут завершаться с помощью двоичного файла Codeception, расположенного в корне вашего проекта. Без этого параметра будет использоваться тот двоичный файл Codeception, который вы первоначально использовали для генерации сценария автозаполнения («Расположение codecept» в приведенных выше примерах).

Заключение

Codeception — это фреймворк, который, возможно, на первый взгляд выглядит простым, но позволяет создавать мощные тесты с помощью одного API, рефакторить их и писать их быстрее с помощью интерактивной консоли. Тесты Codeception легко организовать в группы или классы Cest.

  • Следующая глава: BDD >
  • Предыдущая глава: < Повторное использование кода тестов

© 2011 Michael Bodnarchuk and contributors
Licensed under the MIT License.
https://codeception.com/docs/07-AdvancedUsage

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API