Приемочные (acceptance) тесты

Приемочные тесты — это тесты, которые могут быть выполнены не техническим специалистом. Это может быть Ваш тестировщик, менеджер или даже клиент/заказчик. Если Вы разрабатываете веб-приложение (ведь Вы именно это делаете?), тестировщику необходим только браузер, чтобы убедиться, что приложение работает корректно. В Codeception такого тестировщика мы называем "WebGuy". Вы можете воспроизвести действия пользователя в сценариях и запускать их после каждого изменения сайта. Codeception позволяет делать код тестов простым и понятным, все операции записываются как действия нашего WebGuy.

Не имеет значения какая CMS или Framework используются на сайте. Можно даже тестировать сайты, написанные на других платформах, таких как Java, .NET и т.д. Добавление тестов для Вашего сайта — это отличная идея, на которую стоит потратить время! По крайней мере, Вы будете уверены, что сайт работает корректно после последних изменений.

Простой сценарий

Наверняка, первым сценарием, который Вы захотите запустить, будет авторизация пользователя. Чтобы написать такой сценарий Вам необходимы базовые знания HTML и PHP.

<?php
$I = new WebGuy($scenario);
$I->wantTo('sign in');
$I->amOnPage('/login');
$I->fillField('signin[username]', 'davert');
$I->fillField('signin[password]','qwerty');
$I->click('LOGIN');
$I->see('Welcome, Davert!');
?>

Такой сценарий может быть прочитан и понят даже не техническим специалистом. Codeception может даже преобразовать этот сценарий в текст на английском языке:

I WANT TO SIGN IN
I am on page '/login'
I fill field ['signin[username]', 'davert']
I fill field ['signin[password]', 'qwerty']
I click 'LOGIN'
I see 'Welcome, Davert!'

Такое преобразование может быть выполнено командой:

$ php codecept.phar generate:scenarios

Сгенерированные сценарии сохраняются в каталоге "data" основного каталога с тестами.

Этот сценарий может быть выполнен как PHP-браузером, так и обычным браузером через Selenium (или Sahi или ZombieJS). В примерах ниже мы будем писать приёмочные тесты с использованием PHP-браузера. Если у Вас не было опыта работы с Selenium или Sahi - сервером - PHP-браузер будет хорошим выбором для начала.

PHP-браузер

Это наиболее простой и быстрый способ запустить приемочные тесты, так как он не требует фактического запуска браузера. PHP-браузер - это PHP-скрипт, который работает как браузер: отправляет запрос и обрабатывает полученный ответ. В роли PHP-браузера Codeception использует Goutte Web Scrapper, реализованный [Mink]-ом (http://mink.behat.org). В отличии от реальных браузеров, Goutte не поддерживает JavaScript, поэтому Вы не можете проверить реальное отображение элементов HTML-страницы или работу сценариев JavaScript. Хорошая новость состоит в том, что Goutte может быть выполнен в любом окружении. Прежде всего нам понадобится локальная копия сайта. Мы должны указать его URL в конфиге приемочного набора тестов (tests/acceptance.suite.yml).

class_name: WebGuy
modules:
    enabled:
        - PhpBrowser
        - WebHelper
        - Db
    config:
        PhpBrowser:
            url: [адрес вашего сайта]

Следует начать с создания 'Cept' файла в папке tests/acceptance . Давайте назовем его SigninCept.php. Мы впишем туда первые строчки:

<?php
$I = new WebGuy($scenario);
$I->wantTo('sign in with valid account');
?>

Секция wantTo вкратце описывает Ваш сценарий. Там расположены дополнительные закомментированные методы, нужные для создания Codeception сценария BDD истории. Если Вы когда-либо писали BDD сценарий в Gherkin, Вы сможете перевести классическую историю в Codeception код:

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

превращается в:

<?php
$I = new WebGuy($scenario);
$I->am('Account Holder'); 
$I->wantTo('withdraw cash from an ATM');
$I->lookForwardTo('get money when the bank is closed');
?>

История описана, приступим к написанию сценария:

объект $I служит для записи всех взаимодействий. Методы объекта $I берутся из модулей PHPBrowser и Db. Здесь мы кратко опишем процесс, но для полной картины пройдите по ссылке здесь Codeception.com.

<?php
$I->amOnPage('/login');
?>

Мы подразумеваем, что всё am команды должны описывать стартовое окружение. Команда amOnPage устанавливает начальную точку теста на странице /login. По умолчанию браузер открывает главную страницу Вашего локального сайта.

С помощью PhpBrowser Вы можете кликать по ссылкам и заполнять формы. Возможно, это будут Ваши основные действия.

Click (Клик)

Эмулирует клики по валидным якорям. Страница будет открыта исходя из атрибута "href". В качестве параметра Вы можете указать имя ссылки или валидный CSS селектор. Перед переходом по ссылке, Вы можете проверить, действительно ли ссылка присутствует на странице. Это может быть выполнено с помощью action-а seeLink.

<?php
$I->click('Log in'); 
// CSS selector applied
$I->click('#login a');
// checking that link actually exists
$I->seeLink('Login');
$I->seeLink('Login','/login');
$I->seeLink('#login a','/login');
?>

Forms (Формы)

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

Давайте засабмитим наш пример формы внутри Codeception теста:

<form method="post" action="/update" id="update_form">
     <label for="user_name">Name</label>
     <input type="text" name="user[name]" id="user_name" />
     <label for="user_email">Email</label>
     <input type="text" name="user[email]" id="user_email" />     
     <label for="user_gender">Gender</label>
     <select id="user_gender" name="user[gender]">
          <option value="m">Male</option>
          <option value="f">Female</option>
     </select>     
     <input type="submit" value="Update" />
</form>

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

<?php
// we are using label to match user_name field
$I->fillField('Name', 'Miles');
// we can use input name, or id
$I->fillField('user[email]','miles@davis.com');
$I->selectOption('Gender','Male');
$I->click('Update');
?>

Чтобы найти поля по их "лэйблам" (labels), Вам следует вписать атрибут for в тэг лэйбла.

С точки же зрения разработчика, сабмит формы - это просто отправка корректногого POST запроса на сервер. Иногда проще сразу заполнить все поля и отправить форму без нажатия кнопки 'Submit'. Похожий сценарий мождет быть переписан с помощью одной единственной команды.

<?php
$I->submitForm('#update_form', array('user' => array(
     'name' => 'Miles',
     'email' => 'Davis',
     'gender' => 'm'
)));
?>

submitForm - это не эмуляция действий пользователя. Использование этого метода довольно полезно в ситуациях, когда форма некорректно отформатирована. Независимо от того, установлены ли метки, имеют ли поля некорретные имена или ID, или же форма отправляется с помощью javascript, submitForm будет весьма полезен. Рассмотрите возможность использования этого метода для тестирования страниц с некорректным HTML-кодом.

Также следует заметить, что метод submitForm не может быть выполнен в Selenium.

Эмуляция AJAX

Как мы знаем, PHP-браузер не может обрабатывать javascript. Тем не менее, все ajax вызовы могут быть просто сэмулированы с помощью отправки верного GET или POST запроса на сервер. Подумайте о возможности использования этих методов для ajax взаимодействия.

<?php
$I->sendAjaxGetRequest('/refresh');
$I->sendAjaxPostRequest('/update',array('name' => 'Miles', 'email' => 'Davis'));
?>

Ассерты

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

<?php
// Проверяем, присутствует ли текст 'Thank you, Miles' на странице.
$I->see('Thank you, Miles');
// Проверяем, что текст 'Thank you Miles' внутри 
// элемента с css классом 'notice'.
$I->see('Thank you, Miles','.notice');
// Или используем XPath
$I->see('Thank you, Miles',"descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]");
// Проверяем отсутствие текста на странице
$I->dontSee('Form is filled incorrectly');
?>

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

Пожалуйста, имейте в виду, что все они начинаются с префикса see.

<?php
$I->seeInCurrentUrl('/user/miles');
$I->seeCheckboxIsChecked('#agree');
$I->seeInField('user[name]','Miles');
$I->seeLink('Login');
?>

Грабберы

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

<?php
$I->fillField('email','miles@davis.com')
$I->click('Generate Password');
$password = $I->grabTextFrom('#password');
$I->click('Login');
$I->fillField('email','miles@davis.com');
$I->fillField('password', $password);
$I->click('Log in!');
?>

Грабберы позволяют Вам получить одно значение с текущей страницы с помощью команд.

<?php
$token = $I->grabTextFrom('.token');
$password = $I->grabTextFrom("descendant::input/descendant::*[@id = 'password']");
$api_key = $I->grabValueFrom('input[name=api]');
?>

Комментарии

На протяжении всего сценария, Вам нужно описывать, какие действия Вы собираетесь выполнить и каких результатов достигнуть. Команды amGoingTo, expect, expectTo помогают сделать создаваемые Вами тесты более наглядными.

<?php
$I->amGoingTo('submit user form with invalid values');
$I->fillField('user[email]','miles');
$I->click('Update');
$I->expect('the for is not submitted');
$I->see('Form is filled incorrectly');
?>

Selenium

Прекрасная возможность Codeception-а состоит в том, что большинство сценариев может быть с легкостью перенесено между тестируемыми бэкэндами (бэкэнд - это код админки, движка, базы данных и т.д., т.е. то, к чему не имеет доступ пользователь/клиент). Ваши тесты PhpBrowser-а, о которых мы писали ранее, могут быть выполнены в Selenium. Единственное,что нам нужно сделать - это переконфигурировать и пересобрать класс WebGuy, чтобы использовать Selenium вместо PhpBrowser-а.

class_name: WebGuy
modules:
    enabled:
        - Selenium
        - WebHelper
    config:
        Selenium:
            url: 'http://localhost/myapp/'
            browser: firefox            

Помните, запуск тестов с помощью PhpBrowser и Selenium сильно различается между собой. Существуют методы, отсутствующие в обоих модулях, например, submitForm, рассмотренный ранее.

Для того, чтобы запустить Selenium-тесты, Вам нужно скачать Selenium Server и запустить его. Если Вы запускаете приемочные тесты с помощью Selenium-а, Firefox будет запущен и все действия будут выполнены шаг за шагом. Команды, которые мы используем в Selenium-е, сильно похожи на те, что есть в PHPBrowser-е. Тем не менее, их поведение может немного отличаться. Все действия, совершенные на странице, вызовут javascript события, которые могли бы обновить содержимое страницы. Поэтому метод click - это не просто загрузка страницы по параметру 'href', но также и возможность выполнить ajax запрос, или сделать элемент видимым.

Кстати, команда see позволяет не просто убедится, что текст внутри элемента существует, но также проверит, что элемент действительно виден пользователю.

<?php 
// will check the element #modal 
// is visible and contains 'Confirm' text.
$I->see('Confirm','#modal'); 
?>

Смотрите документацию по модулю Selenium для полной ясности : ).

Повторное наполнение

В процессе тестирования, Ваши действия могут изменить информацию на странице. Тесты обрушатся при попытке создать или обновить одни и те же данные дважды. Чтобы избежать этого, Ваша БД должна быть подготовлена для каждого теста. Для этой цели Codeception предоставляет модуль Db. Он загрузит дамп базы данных после каждого пройденного теста. Чтобы добиться этого, создайте sql дамп Вашей базы и поместите в папку /tests/data. Установите соединение с базой и укажите путь к дампу в глобальном конфиге Codeception-а.

# В codeception.yml:
modules:
    config:
        Db:
            dsn: '[set pdo dsn here]'
            user: '[set user]'
            password: '[set password]'
            dump: tests/_data/dump.sql

Отладка

Модуль PhpBrowser-а может выводить ценные данные в процессе работы. Просто выполните тесты с опцией --debug чтобы увидеть дополнительный вывод. При каждом провале, скриншот последней отображенной страницы будет сохранен в папке tests/log. PHPBrowser сохранит html код, а Selenium сохранит скриншот страницы.

Чтобы сохранить скриншот текущего окна в любое время, используйте методы модуля WebDebug.

Пользовательские Методы

Если Вам нужно внедрить написанные Вами ассерты или методы, Вы можете расширить класс Helper. Для выполнения операций в текущем состоянии браузера, Вам следует обратиться к объекту Mink Session. Вот как это можно сделать:

<?php

class WebHelper extends \Codeception\Module {

    function seeResponseIsPrettyLong($size = 3000) {
        $session = $this->getModule('PhpBrowser')->session;
        $content = $session->getPage()->getContent();
        $this->assertGreaterThen($size, strlen($content));
    }
}
?>

Мы подключили модуль, затем мы вернули контент из класса [Mink session]. И, наконец, мы выполнили ассерт над текущим контентом (в данном случае, мы проверили, является ли размер полученного контента больше, чем $size = 3000. Мы выдвинули утверждение, что он не должен, по сути, быть больше, чем нам нужно :).

Чтобы заглянуть глубже, Вам определенно следует изучить Mink :).

Заключение

Написание приемочных тестов с помощью Codeception и PhpBrowser - хорошее начало. Вы с легкостью можете проверить Ваши сайты на Joomla, Drupal, Wordpress также, как и созданные на других фреймворках. Написание приемочных тестов — это все равно, что описывать действия тестировщика на PHP. Они достаточно хорошо читабельны и очень просты в написании.

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

Трудились и переводили ребята из amyLabs Дополнил перевод Рымаров Владислав