页面对象模式设计

时间:2014-10-27 06:52:50

标签: java selenium-webdriver automation build-automation

我去了链接后的页面对象模式,概念很好,

https://code.google.com/p/selenium/wiki/PageObjects

这是我的疑问:

public LoginPage typeUsername(String username) {
    driver.findElement(usernameLocator).sendKeys(username);
    return this;    
}

public LoginPage typePassword(String password) {
    driver.findElement(passwordLocator).sendKeys(password);
    return this;    
}


public HomePage submitLogin() {    
   driver.findElement(loginButtonLocator).submit();
    return new HomePage(driver);    
}

上面的selenium调用包含了一些函数,我们在testcase或任何页面级函数中调用这些函数,如下所示:

 public HomePage loginAs(String username, String password) {

        typeUsername(username);
        typePassword(password);
        return submitLogin();
    }

我的疑问是:为什么我们不能直接调用sendkey或在整个项目中每次提交或点击。只有一行代码我们用自己的函数包装,这将花费更多的时间来运行代码。

是否有任何性能问题?

3 个答案:

答案 0 :(得分:1)

恕我直言,关键的好处是页面对象和测试是独立发展的。如果有结构更改,您不会更改测试,反之亦然,如果您想要更改您正在测试的内容,则无需更改页面对象。将试图在一个例子中说明这一点

考虑在不遵守页面对象模式的情况下编写的测试,例如:测试产品细节。

this.driver(Find.By.id("username")).sendKeys(username);
this.driver(Find.By.id("pass")).sendKeys(password);
this.driver(Find.By.id("submit")).click();
// navigate to product listing page
this.driver(Find.By.id("product-usb")).click();
// navigate to product details page
this.driver(Find.By.id("product-a")).click();
assert(this and that);

在此示例中,如果发生结构更改(主要重新设计),您将强制更改测试。 现在,您预计会发生变化,首先,您要确保没有代码重复,这样您才能在时间正确的情况下在一个地方进行更改。您在方法中拆分代码,最合理的拆分基于逻辑单元,而断言保留在它们所属的测试中

   login(username, password);
   moveToProductListing();
   selectProduct(productID);
   assert(this and that);

问题在于应该实现这些方法,以便您可以在测试中轻松访问它们。如果它是一个实用程序类,它将很快变得臃肿。进一步思考将引导您按页面对象进行分组。

你的测试最终不知道被测试页面的结构(它隐藏在页面对象中),以及页面对象对你正在进行的测试特定断言一无所知。

答案 1 :(得分:1)

因为您已经开始使用Selenium文档了。如果你看看这些Test design considerations,我认为这也会有所帮助。作为@Master Slave回答的补充,你会看到

  

包装Selenium电话

     

与任何编程一样,您将需要使用   实用程序函数来处理否则将被复制的代码   在整个测试中。防止这种情况的一种方法是经常包装   使用了您自己的函数或类方法的selenium调用   设计。

并使用WebElements Presence的“安全操作”进行扩展。

关于Page对象,很高兴阅读PageFactory的提示。

答案 2 :(得分:0)

我认为这个问题和你的怀疑是围绕着基本的,更多的是我会尝试回答

究竟什么是Page Object设计模式?

嗯,页面对象是您系统中的页面(或视图)的某种API,让我们将其视为页面为测试人员提供的“服务”......

一旦被视为如此,我相信更容易想到动机......

页面对象知道其匹配的HTML页面(或视图)的内部,它只知道它......

例如,如果我们想要执行登录(作为用户),我们将为您提供以下服务:

  • 我们在用户名输入中输入用户名。
  • 我们可以在密码输入中输入密码。
  • 我们可以点击“登录”按钮(期待失败或成功)。

当然还有更多的“服务”,但我们可以在这里停下来回到这一点......我们应该对这些“服务”做些什么?这很简单:

我们需要创建一个“LoginPage”对象,它知道页面的(私有)选择器和HTML构造(id,类,xpath等等)。测试人员的公开内容是什么?我们刚才谈到的服务......

测试人员可以向登录页面询问“TypeUsername(string inputUsername)”或TypePassword(string inputPassword) - 如果您使用此页面测试其他页面,您还可以添加“LoginAsDefaultUser()”之类的“服务”... < / p>

问题

虽然这是一个良好的开端,但仍有很大的改进空间。

最明显的问题是,我们可能需要跨多个页面对象执行常见操作。使用我们当前的方法,我们最终会得到重复的代码。

解决方案

当创建包装Selenium核心的BasePage对象,并且每个页面从该页面继承(直接或直接)时,我们正在创建一个未耦合的动态环境,如果某个页面(或视图)发生了变化,则需要只修复一个特定对象。

<强>摘要

  • 尽管它被称为页面对象设计模式,但它更像是一个视图对象设计模式,例如:如果在您的平台中有一个左侧菜单在每个页面上返回,您可以创建“MyPlatformBasePage”并且每个视图将从它继承(并且代码重复再次消失,胜利!)
  • 页面对象仅公开提供的“服务”,不公开Selenium内部。
  • Page Object不是测试,不要对其结果断言。
  • 方法返回其他PageObjects,例如:调用'LoginAsDefaultUser'的LoginPage将导航到我们的应用程序主页,因此我们必须返回“HomePage”对象。
  • 使用干净的代码主体,您提供的不同“服务”将以不同的方式表示,不要通过布尔值来改变“服务”的逻辑。

<强>动机

  • 现在每个人都可以编写这些测试,甚至是非技术QAs
  • 现在代码是完整的动态和封装的
  • 使用外观层(或基页),您可以潜在地替换Selenium或更改版本而不会有太大的麻烦。