代码接收,使用页面对象设计模式和小黄瓜编写验收测试

2022-08-30 10:03:08

我正在寻找一个简单的代码示例,其中包含页面Object设计模式和小黄瓜,因为当我遵循codeception BDD文档时,所有在测试/支持/验收测试器中编写的示例.php。我不明白(英语能力差--)为什么不把所有的代码都集中在Incepttester.php文件中。

例如,我有一个示例主页,其中包含两个按钮 A 和 B。如果用户单击按钮 A,则加载页面 A,否则如果用户单击按钮 B,则加载页面 B。

目前,我的验收测试员

<?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”,一切都像一个超级按钮一样工作。但正如我之前所说,我需要学习如何不将所有代码集中在InceptTester文件中。

所以,我创建了三个页面对象;一个用于主页,一个用于页面 A,一个用于页面 B。验证码 :

主页对象

<?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 页面对象

<?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 页面对象

<?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;
    }
}

然后,我创建了三个步骤对象;homeChecker, goToPageA, goToPageB

主检查器步骤对象

<?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);
    }
}

页面AChecker 步骤对象

<?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);
    }

}

PageBChecker 步骤对象

<?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);
    }

}

而现在,我不知道我必须做什么。如果我清空我的Incepttester文件并再次运行'./vendor/bin/codecept run accept'命令,测试是不完整的,并且在我的shell中收到“在上下文中找不到”警告:

enter image description here

我该怎么办?

更新我在这里的codeception GitHub中创建了一个帖子:

https://github.com/Codeception/Codeception/issues/5157

我描述了一个重现我的问题的最小示例和一个(非常)丑陋的解决方案。我希望得到一个好方法,并理解为什么我描述不起作用!


答案 1

我在 shell 中收到“在上下文中找不到”警告

好的,如何将小黄瓜文件执行与我自己的上下文类(页面对象,步骤对象等)中定义的步骤链接起来?我们可以阅读Codeception文档中的“BDD>配置”一章:

如前所述,步骤应该在上下文类中定义。默认情况下,所有步骤都在Actor类中定义,例如,验收测试器。但是,您可以包含更多上下文。这可以在全局 codeception.yml 或套件配置文件中进行配置:

gherkin:
    contexts:
        default:
            - AcceptanceTester
            - AdditionalSteps
            - PageHome
            - HomeChekcer

(...)通过这种方式,页面对象、帮助程序和步骤对象也可以成为上下文。


更好

如果我们继续阅读:

但更可取的做法是按上下文类的标记或角色包含上下文类。

这意味着,考虑到可识别性和良好的组织,您不会希望使用每个页面对象来超载每个测试。因此,您可以按角色、标记或路径分配页面对象(或任何助手类)。请参阅有关文档的后续段落。按照您的示例,并按标记进行分配:

gherkin:
   contexts:
      default:
         - AcceptanceTester
      tag:
         myTagX:
             - Page\Acceotance\HomePage\HomeChecker
             - Page\PageHome
         anotherTag:
             - Page\Acceotance\another\AnotherChecker
             - Page\PageAnother

...和在小黄瓜文件中:

@myTagX
Feature
(...)

答案 2

正如我所看到的,您正在尝试以可重用的方式编写自动化层。您可以为其使用“屏幕播放”模式。

这里讨论页面对象和剧本之间的差异

关键区别在于剧本模式组织了页面对象。

John Ferguson 文章:剧本:自动化验收测试的下一阶段


推荐