我还没有找到
Internet上具有用于
Codeception的
Page Object设计模式的Gherkin实现的单个具体示例,所以我认为向Internet讲述我们自己的这种模式的实现并不合适。
本文的目的是为那些已经稍微熟悉Codeception或类似框架,但还不知道如何使用测试对象来使测试更具可读性,简化其支持并减少额外代码量的人。 尽管如此,我还是试图逐步解释从头开始组装自动化项目的所有要点。
Page Object模板使您可以使用page元素封装工作,从而可以减少代码量并简化其支持。 UI中的所有更改都可以轻松快速地实现-只需更新描述此页面的Page Object类即可。 这种体系结构方法的另一个重要优点是,它使您不必使HTML测试脚本的细节杂乱无章,这使它更易于理解和理解。
这是不使用Page Object的情况下的外观

使用页面对象

我不会详细介绍安装基本环境,我将提供初始数据:
- Ubuntu仿生海狸
- PHP 7.1.19-1
- Composer-PHP依赖管理器,已全局安装
- PhpStorm-开发环境
要运行测试,我们还需要:
扩展代码接收
继续安装Codeception:
我们在终端中打开所需目录,在该目录中我们将收集项目,或者为该项目创建目录并转到该目录:
mkdir ProjectTutorial cd ProjectTutorial
安装Codeception框架及其依赖项:
composer require codeception/codeception --dev

项目中的composer.json依赖项安装文件如下所示:
{ "require": { "php": ">=5.6.0 <8.0", "facebook/webdriver": ">=1.1.3 <2.0", "behat/gherkin": "^4.4.0", "codeception/phpunit-wrapper": "^6.0.9|^7.0.6" }, "require-dev": { "codeception/codeception": "^2.5", "codeception/base": "^2.5" } }
展开项目:
php vendor/bin/codecept bootstrap

有关如何安装该项目的更多信息,请参见
官方文档 。
在此阶段,在我们的项目中创建了三组测试。 默认情况下,Codeception将它们分为接受,功能和单位。 对于这些集合,Codeception还生成了三个yml文件。 在其中,我们指示所有必需的
配置 ,连接模块和属性以运行测试。
本课基于验收测试的示例,因此我将在Acceptance.suite.yml中进行设置。
在PHP Storm(或其他喜欢的开发环境)中打开我们的项目,然后转到
Acceptance.suite.yml (默认情况下,它位于tests / accepting.suite.yml文件夹中)。
我们写下最小的必要依赖项,并始终注意格式化。 模块之间用“-”号隔开,并且必须处于同一级别,否则测试开始时错误会散布。
原来:
actor: AcceptanceTester modules: enabled: - WebDriver: url: 'http://yandex.ru/' // , browser: 'chrome' - \Helper\Acceptance // gherkin: contexts: default: - AcceptanceTester
还有一些准备工作:
在项目根目录(我有lib)中创建一个单独的目录。
在此目录中,创建可执行文件run.sh,它将运行Selenium和Chrome驱动程序。
我们将Selenium和Chrome驱动程序放在这里,并在run.sh中编写run命令:
java -jar -Dwebdriver.chrome.driver=chromedriver_241 selenium-server-standalone-3.14.0.jar
在项目中的外观:

我们返回控制台并更改访问权限:
chmod +x ./run.sh
(注意。位于目录中的驱动程序名称必须与start命令中指定的名称完全匹配)。您可以立即启动Selenium和Webdriver,以免再次出现此问题。 为此,请打开一个新的终端选项卡,转到run.sh文件所在的目录并编写启动命令:
~/AutomationProjects/ProjectTutorial/lib$ ./run.sh
确保服务器正在运行:

我们使其处于运行状态。 至此准备工作就完成了。
编写测试脚本
我们继续为测试用例创建功能部件文件。 为此,在Codeception中提供了一个特殊的命令,在控制台中运行它:
cept g:feature acceptance check
(请注意“检查”-测试的名称)我们在接受文件夹中看到了新的check.feature文件。

我们不需要默认内容,我们将其立即删除并编写测试。
为了使收集者能够识别西里尔字母,请不要忘记使用#language:ru启动脚本。
我们正在用俄语写一个简短的剧本。 谨在此提醒您,每个句子都应以以下关键字开头:“ When”,“ Then”,“ And”,符号“ *”等。
对于我的示例,我访问了Yandex网站,您可以选择任何一个。

要查看测试中有哪些步骤,我们在终端中运行脚本:
cept dry-run acceptance check.feature

脚本的步骤显示在控制台中,但尚不可用。
然后,我们运行一个命令,该命令将自动生成用于实现我们的方法的模板:
cept gherkin:snippets acceptance

脚本中所有用引号引起来的名称均替换为变量:arg。
我们从终端复制它们,然后将其粘贴到
AcceptanceTester.php文件中,该文件位于使用页面元素的方法中。

将方法重命名为可读的方法,以反映其本质(可选),并编写其实现。

一切都很简单,但是如果您在智能开发环境(例如Storm)中工作,则一切都会更加简单,该环境本身会提示来自库的必要命令:

我们删除多余的部分并编写方法:
public function step_beingOnMainPage($page) { $this->amOnPage('/'); } public function step_seeElement($element) { this->seeElement($element); } public function step_clickOnButton($button) { $this->click($button); } public function step_fillField($field, $text) { $this->fillField($field, $text); }
让我们看看发生了什么。 我们成立了一个团队,向我们展示我们现在实现了哪些方法(步骤)。
cept gherkin:steps acceptance

成功!
但是,功能文件中的步骤仍未被识别为方法。

为了让Storm了解如何执行这些步骤,我们将通过在名称空间Gherkin Context中实现Context接口来做一个技巧。
namespace Behat\Behat\Context { interface Context {} }
将我们的AcceptanceTester类包装在名称空间中并从Context继承
implements \Behat\Behat\Context\Context

现在,功能文件的所有步骤都与它们的实现相关联:

为了使Webdriver了解单击的内容和查找的位置,您需要用相应的定位符和URL替换可读元素的名称和页面地址,这些将作为参数放入方法中。
然后我们得到以下形式的测试:

您可以运行:
cept run acceptance

已通过
大约 如果页面元素需要很长时间加载,则可以将wait添加到所需的方法中:
$this->waitForElementVisible($element);
我们回到测试场景。 我们感到沮丧的是,由于我们看到的不是HTML元素和url,而是元素和页面的明确名称,因此失去了整个测试的可读性。
如果我们要解决此问题,是时候继续执行Page Object模式的实现了。
转到页面对象
在_support目录中,创建Page目录,我们将在其中放置我们的类页面:
php vendor/bin/codecept generate:pageobject MainPage
第一个Page Object是Yandex的主页,我们称它为MainPage,我们将类称为相同:

在这里,我们声明静态字段和方法,以便可以在不创建对象的情况下调用它们。
由于在Acceptance.suite.yml的配置中,我们已经指定了起始页面网址:
yandex.ru ,对于主页而言,足以指定
public static $URL = '/';
接下来是页面元素数组。 我们描述了几个元素的定位符,并为其赋予了明确且唯一的名称。
现在,您需要添加getElement方法,该方法将通过数组中元素的名称返回定位符。
结果,我们有:
<?php //location: tests/_support/Page/MainPage.php namespace Page; /** */ class MainPage { public static $URL = '/'; public static $elements = array( ' ' => "//*[@id='wd-wrapper-_afisha']", ' ' => "//*[@data-statlog='afisha.title.link']", ' ' => "//*[@class='weather__icon weather__icon_ovc']|//*[@class='weather__icon weather__icon_skc_d']", ); public static function getElement($name){ return self::$elements[$name]; } }
添加几个页面类:
/ **海报* /

/ **海报-搜索结果* /

我们返回到
AcceptanceTester.php类,在其中编写了方法。
让我们在其中创建一个PageObject类的数组,在这里我们将名称分配给页面并在命名空间中指示它们的类名称:
private $pages = array( " " => "\Page\MainPage", "" => "\Page\AfishaPage", " - " => "\Page\AfishaResult" );
每个新的PageObject都类似地添加到此数组。
接下来,我们需要创建currentPage字段,该字段将存储指向当前页面的PageObject的链接:
private $currentPage;
现在,我们将编写一个方法,当该方法被调用时,我们可以获取currentPage并初始化所需的PageObject类。
使用“当用户导航到“页面名称”页面时”采取这样的步骤是合乎逻辑的。 然后,无需检查即可初始化PageObject类的最简单方法如下所示:
/** * @When :page */ public function step_beingOn($page) { // pageObject $this->currentPage = $this->pages[$page]; }
现在,我们编写getPageElement方法,该方法将使我们能够从当前页面获取元素,或更确切地说是其定位符:
private function getPageElement($elementName) { // $curPage = $this->currentPage; return $curPage::getElement($elementName); }

对于已经实现的方法,有必要用PageObject的元素替换我们在一开始就直接从功能文本接收的参数,即:
$arg
将采取的形式
getPageElement($arg))
然后我们的方法将采用以下形式:
/** * @When :page */ public function step_beingOnMainPage($page) { // pageObject $this->currentPage = $this->pages[$page]; $curPage = $this->currentPage; $this->amOnPage($curPage::$URL); } /** * @Then :element */ public function step_seeElement($element) { $this->waitForElementVisible($this->getPageElement($element)); $this->seeElement($this->getPageElement($element)); } /** * @Then :button */ public function step_clickOnButton($button) { $this->click($this->getPageElement($button)); } /** * @Then :field :text */ public function step_fillField($field, $text) { $this->fillField($this->getPageElement($field), $text); } /** * @Then :field */ public function step_deleteText($field) { $this->clearField($this->getPageElement($field)); }
通过按Enter添加了另一种显示搜索结果的方法:
public function step_keyboardButton() { $this->pressKey('//input',WebDriverKeys::ENTER); }
最后一步是在描述所有必需的方法和PageObjects时,您需要重构测试本身。 添加将在进入新页面时初始化PageObject的步骤。 我们有这个“ *用户转到了页面:page”。
为了清楚起见,我将添加更多步骤。 结果是这个测试:
#language: ru : : . . . " " " " " " " " "" " " " " ENTER " - " " " " " " " "" ENTER
这样的测试场景对于任何局外人都是可以理解和理解的。
发射!
要查看更详细的运行结果,可以使用以下命令
cept run acceptance --debug
我们看一下结果:

因此,使用Page Object模式可以将所有页面元素与测试脚本分开,并将它们存储在单独的目录中。
该项目本身可以在
https://github.com/Remneva/ProjectTutorial中找到
作为一名自动化工程师,如果您分享您的想法,并且也许告诉我如何在逻辑上尽可能地转变和简化项目结构,我将不胜感激。