【问题标题】:Selenium WebDriver page objectSelenium WebDriver 页面对象
【发布时间】:2012-04-25 12:44:19
【问题描述】:

关于 selenium webdriver 中的页面对象的快速问题。我们的网站非常动态,有很多 ajax 和各种身份验证状态。很难弄清楚如何定义每个页面对象但是可以说我已经弄清楚并定义了几个代表我们网站的页面对象。

你如何处理从一个页面到另一个页面的交叉。所以我得到一个页面对象用于我的主页,一个用于我的帐户页面,一个用于我的结果页面。然后我需要编写一个遍历我所有页面的测试来模拟用户执行多个操作。

你怎么说给我一个 HomePage 对象来创建新用途 -> 然后获取一个帐户页面对象来执行一些用户操作 - 然后获取一个结果页面对象来验证所有来自单个脚本的这些操作。

人们是怎么做到的?

谢谢

【问题讨论】:

  • “页面对象”到底是什么意思?

标签: selenium-webdriver webdriver pageobjects


【解决方案1】:

当您模拟让用户在浏览器的 URL 栏中输入新 URL 时,测试类负责创建它需要的页面对象。

另一方面,当您在页面上执行一些会导致浏览器指向另一个页面的操作时(例如,单击链接或提交表单),则由该页面对象负责返回下一页对象。

由于我不太了解您的主页、帐户页面和结果页面之间的关系,无法准确告诉您它在您的网站中的表现,因此我将使用在线商店应用作为示例.

假设您有一个 SearchPage。当您在 SearchPage 上提交表单时,它会返回一个 ResultsPage。当你点击一个结果时,你会得到一个 ProductPage。所以类看起来像这样(缩写为相关方法):

public class SearchPage {

    public void open() {
        return driver.get(url);
    }

    public ResultsPage search(String term) {
        // Code to enter the term into the search box goes here
        // Code to click the submit button goes here
        return new ResultsPage();
    }

}

public class ResultsPage {

    public ProductPage openResult(int resultNumber) {
        // Code to locate the relevant result link and click on it
        return new ProductPage();
    }

}

执行这个故事的测试方法如下所示:

@Test
public void testSearch() {

    // Here we want to simulate the user going to the search page
    // as if opening a browser and entering the URL in the address bar. 
    // So we instantiate it here in the test code.

    SearchPage searchPage = new SearchPage();
    searchPage.open(); // calls driver.get() on the correct URL

    // Now search for "video games"

    ResultsPage videoGameResultsPage = searchPage.search("video games");

    // Now open the first result

    ProductPage firstProductPage = videoGameResultsPage.openResult(0);

    // Some assertion would probably go here

}

如您所见,页面对象存在这种“链接”,其中每个对象都返回下一个对象。

结果是您最终会得到许多不同的页面对象来实例化其他页面对象。因此,如果您有一个相当大的网站,您可以考虑使用依赖注入框架来创建这些页面对象。

【讨论】:

  • 这是我认为我需要做的。看起来有点笨拙,因为我们的网站非常 ajaxy,网站上的操作会根据用户当前所处的状态返回不同的位置。
  • 这段代码的问题是每个页面都需要调用 PageFactory.initObjects() 并且驱动程序实例无法初始化 2 个不同页面上的所有对象(假设它们是 2 个不同的窗口或嵌入式框架) .所以,虽然我同意这对很多事情来说都是一个很好的设计模式,但这种模式很快就会分解为只适用于某些应用程序。 WebDriver PageFactory 的设计方式,打开一个页面对象,使用它,将其标记为垃圾收集,然后实例化下一页,使用它等要好得多。也许你可以扩展 PageFactory,作为一种解决方法,也许。跨度>
【解决方案2】:

好吧,我创建了自己的代表页面的 Java 类:

说,下面是代表主页的代码。这里用户可以登录:

public class HomePage{
  private WebDriver driver;
  private WebElement loginInput;
  private WebElement passwordInput;
  private WebElement loginSubmit;

  public WebDriver getDriver(){
    return driver;
  }

  public HomePage(){
    driver = new FirefoxDriver();
   }

  public CustomerPage login(String username, String password){
     driver.get("http://the-test-page.com");
     loginInput = driver.findElement(By.id("username"));
     loginInput.sendKeys(username);
     passwordInput = driver.findElement(By.id("password"));
     passwordInput.sendKeys(password);
     loginSubmit = driver.findElement(By.id("login"));
     loginSubmit.click();
     return new CustomerPage(this);
  }


}

Customer 页面可能如下所示。在这里,我正在演示如何获取登录用户:

public class CustomerPage{
    private HomePage homePage;
    private WebElement loggedInUserSpan;

 public CustomerPage(HomePage hp){
    this.homePage = hp;
  }

 public String getLoggedInUser(){
      loggedInUserSpan = homePage.getDriver().findElement(By.id("usrLongName"));
      return loggedInUserSpan.getText();
 }

}

测试可以这样进行:

@Test
public void testLogin(){
  HomePage home = new HomePage();
  CustomerPage customer = home.login("janipav", "extrasecretpassword");
  Assert.assertEquals(customer.getLoggedInUser(), "Pavel Janicek");
}

【讨论】:

    【解决方案3】:

    您通常希望对用户在使用您的网站时的实际行为进行建模。当使用页面对象时,这最终会采用领域特定语言 (DSL) 的形式。但是,它会与可重用的页面组件混淆。

    现在 Java 8 推出了默认方法,可重用的页面组件可以被视为使用默认方法的 mixin。我有一篇博客文章,其中包含一些在这里找到的代码示例,更详细地解释了这一点:http://blog.jsdevel.me/2015/04/pageobjects-done-right-in-java-8.html

    【讨论】:

      【解决方案4】:

      我建议您使用为这些模式提供支持的框架。 Geb 是目前最好的之一。以下是他们手册中的示例

      Browser.drive {
          to LoginPage
          assert at(LoginPage)
          loginForm.with {
              username = "admin"
              password = "password"
          }
          loginButton.click()
          assert at(AdminPage)
      }
      
      class LoginPage extends Page {
          static url = "http://myapp.com/login"
          static at = { heading.text() == "Please Login" }
          static content = {
              heading { $("h1") }
              loginForm { $("form.login") }
              loginButton(to: AdminPage) { loginForm.login() }
          }
      }
      
      class AdminPage extends Page {
          static at = { heading.text() == "Admin Section" }
          static content = {
              heading { $("h1") }
          }
      }
      

      【讨论】:

        【解决方案5】:

        我喜欢使用页面对象模式编写 Selenium Webdriver 测试。但个人对必须始终显式实例化并返回下一页或页面组件的冗长和重复感到恼火。因此,借助 Python 的元类,我写了一个 library, called Keteparaha, that automatically figures out what should be returned from a selenium page object's method calls

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-08-09
          • 1970-01-01
          • 2013-08-10
          • 2019-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-18
          相关资源
          最近更新 更多