是否应该使元素在页面对象之外可用?

Dub*_*Dev 7 automated-tests webdriver pageobjects selenium-webdriver protractor

这是一个我无法找到确切来源的问题,希望基于用户以前的经验获得一些答案,主要是解释为什么某种方法无法解决

我正在通过Protractor使用webdriver进行自动化,并且正在争论是否应在页面对象本身之外使页面元素可用。经过研究,人们似乎采取了几种不同的方法,但我无法完全掌握每种方法的长期含义。

我已经看到页面对象模型的以下不同实现:


定位符在页面对象中声明并导出

这是我最不喜欢的方法,因为这意味着在测试中实际上已识别出元素。设置这似乎是一个糟糕的标准,因为它可能会鼓励自动化人员直接在应用程序中使用新的定位器,而不是页面对象。同样,在初始化PO时,不能直接设置任何需要动态信息的参数,需要进一步编辑。

pageobject.js

export default class HomePage {
    constructor() {
        this.passwordField = '#password';
        this.usernameField = '#user';
    }
}
Run Code Online (Sandbox Code Playgroud)

test.js

const homePage = new HomePage();
$(homePage.usernameField ).sendKeys('admin');
$(homePage.passwordField ).sendKeys('password');
Run Code Online (Sandbox Code Playgroud)

在页面对象中声明并导出的元素,而不是定位符

pageobject.js

export default class HomePage {
    constructor() {
        this.passwordField = $('#password');
        this.usernameField = $('#user');
    }
}
Run Code Online (Sandbox Code Playgroud)

test.js

const homePage = new HomePage();
homePage.usernameField.sendKeys('admin);
homePage.passwordField.sendKeys('password);
Run Code Online (Sandbox Code Playgroud)

在页面对象中声明的元素,仅在页面对象中直接使用,仅导出方法

这是我过去使用的方法,最终我们获得了许多功能。例如setUsename(), getCurrentUsername(), getUsernameAttibute(), verifyUsernameExists()password元素和许多其他元素具有和。我们的页面对象变得巨大,所以我觉得这不再是最好的方法。但是,优点之一是我们的测试看起来很干净而且可读性很强。

pageobject.js

export default class HomePage {
    constructor() {
        var passwordField= $('#password');
        var usernameField = $('#user');
    }

    setUserName(name){
       username.sendKeys(name);
    };

    setPassword(password){
       passwordField.sendKeys(password);
    };
}
Run Code Online (Sandbox Code Playgroud)

test.js

const homePage = new HomePage();
homePage.setUsername('admin');
homePage.setPassword('123');
Run Code Online (Sandbox Code Playgroud)

我很想获得对此的一些反馈,因此希望您可以花些时间阅读。

Rak*_*uri 5

我更喜欢并相信最后一种方法是最好的。

撇开我们谈论自动化的事实不谈,任何好的/伟大的软件都具有以下特征。

  • 单独的模块/件/组件组成
  • 每个单独的模块/部分/组件在数据/信息(选择器、自动化情况下的 webdriver API 调用)方面都是内聚的,特定于其 API/方法与数据交互。

最后一种方法提供了您指出的测试清洁度的额外好处。

然而,大多数时候,无论出于何种原因,我们都倾向于忽略模块化并让现有的 PO 变得臃肿。这是我见过的并且是其中的一部分。因此,在某种程度上,PO 变得臃肿并不是因为方法,而是因为自动化人员/测试人员/开发人员有意识地保持 PO 模块化、组合和简单的方式。无论是关于 PO 还是应用程序功能代码都是如此

划船 PO:

具体到PO臃肿的问题,看看能不能把PO中的公共元素分出来。例如。页眉、页脚、左导航、右导航等在页面之间是通用的。它们可以被分离出来,并且 PO 可以那些单独的部分/部分组成。

即使在主要内容中,如果其合乎逻辑并且可以跨页面重用,将公共内容(如果它跨两个或多个页面,如果不是全部)分离到它们自己的组件 API 中。

自动化规范对 ex 执行广泛的回归是正常的。一个元素是一个密码字段,文本框的长度是某某等等。在这种情况下,为每个规范用例(或期望)添加方法是没有意义的。好消息是,这里的共性也占据了中心位置。基本上,提供跨规范使用的 API,而不是在一个规范中使用的 API。

以ex为例。密码字段应该被屏蔽。您不太可能想在多个规范文件中测试它。在这里,我们可以在LoginPOlike 中为它添加一个方法,isPasswordMasked() 或者我们可以让密码字段可访问,LoginPO并且规范对密码类型字段进行实际检查。通过这样做,我们仍然让LoginPO在密码字段信息的控制,可向其他API(事务login()logout()等等),即只有PO知道如何以及在何处获取密码元素。具有将规范测试推送到规范文件的额外优势。

该采购订单expect/assert

在任何时候,将任何测试(或)作为 PO API 的一部分都不是一个好主意expect。原因:

  • PO 及其 API 可跨套件重用,任何人都应该易于查看和理解。他们的主要职责是提供通用 API。
  • 他们应该尽可能瘦(以防止腹胀)
  • 更重要的是,浏览器自动化本身就较慢。如果我们在 PO 及其 API 方法中添加测试逻辑,只会让它变慢。

FWIW,我还没有遇到任何要求使用臃肿 API 的网页。

暴露 PO 中的元素:

这取决于我相信的用例。可能是仅在一个规范中使用的元素可以是要公开的基本情况。也就是说,一般来说,这个想法是规范应该对测试人员/开发人员以及以后查看它们的人来说是可读的。无论是使用有意义的元素变量名称还是方法名称完成,充其量只是一种偏好。另一方面,如果一个元素意味着有一些涉及交互(例如悬停打开菜单链接),它绝对是单独通过 API 公开的候选者。

希望增加一些澄清!


Jef*_*ffC 5

最后一种方式是实现页面对象的正确方式。页面对象背后的想法是它隐藏了页面的内部结构,并为脚本调用提供了一个干净的 API,以在页面上执行操作。定位器和元素不应暴露。您需要对页面执行的任何操作都应该通过公共方法公开。

避免页面上每个字段都使用 getter 和 setter 的一种方法是合并方法。考虑用户将在页面上执行的操作。与其使用.setUsername().setPassword().clickLoginButton()方法,您应该只拥有一个login()将用户名和密码作为参数并完成所有登录工作的方法。

参考

Martin Fowler 通常被认为是“页面对象”概念的发明者,但其他人创造了“页面对象”这个名称。参见他对页面对象的描述

Selenium 关于页面对象的文档。