Codeception, записывать приемочные тесты с шаблоном проектирования страницы и объектами оргстекла
Я ищу простой пример кода с шаблоном проектирования pageObject и gherkin, потому что, когда я следую документации BDD кодового кода, все примеры написаны в тестах/поддержке /AcceptanceTester.php. Я не понимаю (плохое знание английского языка) - как не сконфигурировать весь код в файле AcceptanceTester.php.
Например, у меня есть примерная домашняя страница с двумя кнопками A и B. Если пользователь нажимает кнопку A, страница A загружается иначе, если пользователь нажимает кнопку B, загружается страница B.
В настоящее время мой AcceptanceTester:
<?php
// tests/_support/AcceptanceTester.php
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class AcceptanceTester extends \Codeception\Actor
{
use _generated\AcceptanceTesterActions;
/**
* @Given The home page
*/
public function inHomePage()
{
$this->amOnPage("/");
$this->seeInTitle('home');
}
/**
* @When I click on the button A
*/
public function goToThePageA()
{
$this->click(['name' => 'A']);
}
/**
* @Then l go to the page A
*/
public function ImInPageA()
{
$this->seeInTitle('page A');
}
/**
* @When I click on the button B
*/
public function goToThePageB()
{
$this->click(['name' => 'B']);
}
/**
* @Then l go to the page B
*/
public function ImInPageB()
{
$this->seeInTitle('page B');
}
}
Если я запустил команду "./vendor/bin/codecept run accept", все работает как шарм. Но, как я сказал ранее, я хочу узнать, как не сконфигурировать весь код в файле AcceptanceTester.
Итак, я создал три pageObjects; один для главной страницы, один для страницы A и один для страницы B. Код:
home pageObject:
<?php
// tests/_support/Page/PageHome.php
namespace Page;
class PageHome
{
public static $URL = '/home';
public static $title = "home";
public static $aButton = ['name' => 'A'] ;
public static $bButton = ['name' => 'B'] ;
public static function route($param){
return static::$URL.$param;
}
/**
* @var \AcceptanceTester;
*/
protected $acceptanceTester;
public function __construct(\AcceptanceTester $I){
$this->acceptanceTester = $I;
}
}
A pageObject:
<?php
// tests/_support/Page/PageA.php
namespace Page;
class PageA
{
public static $URL = '/home/pageA';
public static $title = "page A";
public static function route($param){
return static::$URL.$param;
}
/**
* @var \AcceptanceTester;
*/
protected $acceptanceTester;
public function __construct(\AcceptanceTester $I){
$this->acceptanceTester = $I;
}
}
И B pageObject:
<?php
// tests/_support/Page/PageB.php
namespace Page;
class PageB
{
public static $URL = '/home/pageB';
public static $title = "page B";
public static function route($param){
return static::$URL.$param;
}
/**
* @var \AcceptanceTester;
*/
protected $acceptanceTester;
public function __construct(\AcceptanceTester $I){
$this->acceptanceTester = $I;
}
}
Затем я создал три объекта stepObject; homeChecker, goToPageA, goToPageB
Домашняя задача homeChecker:
<?php
// tests/_support/Step/Acceptance/HomeChecker.php
namespace Step\Acceptance;
use Page\Acceotance\HomePage;
class HomeChecker extends \AcceptanceTester
{
/**
* @Given The home page
*/
public function main()
{
$homePage = new PageHome($this);
$this->amOnPage($homePage::URL);
$this->checkTitle($homePage);
$this->checkButtons($homePage);
}
private function checkTitle($homePage){
$this->seeInTitle($homePage::$title);
}
private function checkButtons($homePage){
$this->see($homePage::$aButton);
$this->see($homePage::$bButton);
}
}
PageAChecker stepObject:
<?php
// tests/_support/Step/Acceptance/PageAChecker.php
namespace Step\Acceptance;
use Page\PageHome;
use Page\PageA;
class PageAChecker extends \AcceptanceTester
{
/**
* @When I click on the button A
*/
public function clickButton()
{
$homePage = new PageHome($this);
$this->click($homePage::$aButton);
}
/**
* @Then l go to the page A
*/
public function checkTitle()
{
$aPage = new PageA($this);
$this->seeInTitle($aPage::$title);
}
}
И pageBhecker stepObject:
<?php
// tests/_support/Step/Acceptance/PageBChecker.php
namespace Step\Acceptance;
use Page\PageHome;
use Page\PageB;
class PageBChecker extends \AcceptanceTester
{
/**
* @When I click on the button B
*/
public function clickButton()
{
$homePage = new PageHome($this);
$this->click($homePage::$bButton);
}
/**
* @Then l go to the page B
*/
public function checkTitle()
{
$bPage = new PageB($this);
$this->seeInTitle($bPage::$title);
}
}
И теперь, я не знаю, что я должен делать. Если я выпущу свой файл AcceptanceTester и снова запустил команду "./vendor/bin/codecept run accept", тест будет неполным, и я получу предупреждения "в контекстах" в моей оболочке:
Что я делаю?
Обновление. Я создал сообщение в кодексе github здесь:
https://github.com/Codeception/Codeception/issues/5157
Я описываю минимальный пример для воспроизведения моей проблемы и (очень) уродливого разрешения. Я ищу, чтобы получить хороший способ и понять, почему я описал, не работает!
Ответы
Ответ 1
Я получаю предупреждения "не найдено в контекстах" в моей оболочке
Хорошо, как связать выполнение файлов корнишона с шагами, определенными в моих собственных классах контекстов (PageObjects, StepObjects,...)? Мы можем прочитать главу " BDD> Конфигурация " в документации Codeception:
Как мы упоминали ранее, шаги должны быть определены внутри классов контекста. По умолчанию все шаги определены внутри класса Actor, например, AcceptanceTester. Тем не менее, вы можете включить больше контекстов. Это можно настроить внутри глобального codeception.yml или файла конфигурации пакета:
gherkin:
contexts:
default:
- AcceptanceTester
- AdditionalSteps
- PageHome
- HomeChekcer
(...) Таким образом, PageObjects, Helpers и StepObjects также могут стать контекстами.
Лучше
Если мы продолжим читать:
Но предпочтительнее включать контекстные классы по их тегам или ролям.
Это означает, что, учитывая расширяемость и хорошую организацию, вы не захотите перегружать все тесты каждым объектом Page Object. Поэтому вы можете назначить объект страницы (или любые вспомогательные классы) по роли, тегу или пути. Смотрите следующие параграфы по документации. Следуя вашему примеру, и присваивая теги:
gherkin:
contexts:
default:
- AcceptanceTester
tag:
myTagX:
- Page\Acceotance\HomePage\HomeChecker
- Page\PageHome
anotherTag:
- Page\Acceotance\another\AnotherChecker
- Page\PageAnother
... и в корнишках:
@myTagX
Feature
(...)