【问题标题】:Selenium: optimization of elements defining (Page Object)Selenium:优化元素定义(页面对象)
【发布时间】:2017-12-21 09:41:04
【问题描述】:

我有,例如“注册页面”作为要实现的页面对象之一:

public class SignUpPage {

    WebDriver driver;
    public SignUpPage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }
}

我想从这个页面添加(查找)元素(使用@FindBy),这将在其他方法中使用:

public class SignUpPage {

       WebDriver driver;
       public SignUpPage(WebDriver driver) {
            this.driver = driver;
            PageFactory.initElements(driver, this);
       }

       @FindBy (id = "register-email")
       private WebElement emailField;
       @FindBy (id = "register-confirm-email")
       private WebElement confirmEmailField;
       @FindBy (id = "register-password")
       private WebElement passwordField;

       public SignUpPage typeEmail(String email) {
           emailField.sendKeys(email);
           return this;
       }

       public SignUpPage typeConfirmEmail(String email) {
           confirmEmailField.sendKeys(email);
           return this;
       }
}

有没有更好的方法来组织 @FindBy 注释?例如不要重复这么多次,因为我们有这么多的元素。

【问题讨论】:

  • 感谢下面给出的所有建议,伙计们。我会按工作顺序尝试一切,然后选择答案。
  • 你这样做的方式绝对没问题。您确实需要定义每个元素,因为每个元素都有唯一的 id/选择器/您选择通过什么来查找它。减少重复的唯一方法是在不同的类中重用相同的元素。在这种情况下,您可以将它们存储在父类或某个静态类中。
  • @Dmitry 这是一个简单的框架,我用它来将多个但相似的元素“装箱”到一个变量中 - stackoverflow.com/questions/47195901/…

标签: java selenium selenium-webdriver


【解决方案1】:

您可以尝试将页面分解为不同的对象,以便您可以重复使用其他页面上的某些元素。

如果您查看您的 SignUpPage,它可能包含以下元素: - 导航栏 - 注册表单 - 页脚

如果您查看着陆页,它可能还有导航栏和页脚

如果您为这些元素中的每一个创建一个单独的类,您可以将这些元素添加为每个页面的一部分作为“has-a”关系

public class SignUpPage {
    public SignUpForm signUpForm;
    public NavBar navBar;
    public Footer footer;
    private WebDriver driver;

    public SignUpPage(WebDriver driver) {
        this.driver = driver;
        signUpForm = new SignUpForm(driver);
        navbar = new NavBar(driver);
        footer = new Footer(driver)
    }
}


public class SignUpForm {

      WebDriver driver;
      public SignUpForm(WebDriver driver) {
            this.driver = driver;
            PageFactory.initElements(driver, this);
      }

      @FindBy (id = "register-email")
      private WebElement emailField;
      @FindBy (id = "register-confirm-email")
      private WebElement confirmEmailField;
      @FindBy (id = "register-password")
      private WebElement passwordField;

      public SignUpPage typeEmail(String email) {
          emailField.sendKeys(email);
          return this;
      }

      public SignUpPage typeConfirmEmail(String email) {
          confirmEmailField.sendKeys(email);
          return this;
      }
}

public class NavBar {

      WebDriver driver;
      public NavBar(WebDriver driver) {
            this.driver = driver;
            PageFactory.initElements(driver, this);
      }

      @FindBy (id = "menu")
      private WebElement menu;
}

public class Footer {

      WebDriver driver;
      public Footer(WebDriver driver) {
            this.driver = driver;
            PageFactory.initElements(driver, this);
      }

      @FindBy (id = "contactList")
      private WebElement contactList;
}

如果您将Login(String mail, String password) 之类的方法添加到NavBar 类中,您可以使用类似的东西从每个具有NavBar 的页面调用它

LandingPage.NavBar.Login("me@xyz.com", "s3cr3t");
// Or
LandingPage.NavBar.GoToSignUpPage().SignUp("me@xyz.com", "s3cr3t");

在最后一个例子中,SignUpPage 有一个 SignUpForm 用于调用SignUp

【讨论】:

    【解决方案2】:

    当我们有多个单一标准来识别一个或多个 WebElement 对象时,您可以使用以下之一

    @FindBys

    @FindBys({
      @FindBy(id = "register-email")
      @FindBy(id = "register-confirm-email")
      @FindBy(id = "register-password")
    })
    
    private List<WebElement> elementsWithBoth_EmailANDPassword;
    

    @FindAll:

    @FindAll({
       @FindBy(id = "register-email")
       @FindBy(id = "register-confirm-email")
       @FindBy(id = "register-password")
    })
    
    private List<WebElement> elementsWithBoth_EmailANDPassword 
    

    检查此link。希望这可以帮助。

    【讨论】:

    • FindBys 使用链接。因此,在示例中,它将在“register-confirm-email”元素内找到“register-password”元素,该元素将在“register-email”元素内,依此类推……同样使用 FindAll,它会返回一个列表的 webelement 没有办法区分元素。因此,如果我将 pageobject 代码基于返回元素的顺序并且用户界面发生更改,则 pageobject 将需要修改。
    【解决方案3】:

    当您通过 POM 实现 PageFactory 时,因此在每个 Page Object 中您需要定义每个 WebElement您想在 Page Object 中与谁互动,就像我们在正常情况下重复 driver.findElement()driver.findElements() 的方式一样。

    所以你在上面的点上是正确的。

    话虽如此,您的代码块中仍然存在一些缺陷,如下所示:

    • SignUpPage :页面对象类的 constructorpublic class SignUpPage {} 不应用于初始化 @ 987654331@ 这样。从逻辑上讲,当调用 PageFactory.initElements() 时,页面对象类的 constructor 会自动调用。所以理想情况下,构造函数看起来像:

      WebDriver driver;
      
      //constructor
      public SignUpPage(WebDriver driver)
      {
          this.driver=driver;
      }
      
    • PageFactory.initElements(driver, this)Page Object 的初始化必须由您的Test Class 控制(可能在 @Test 注释下),您可以在其中加载任何Page Object 在运行时根据您的Test Case 要求如下:

      @Test (priority=0)
      public void checkSignUp()
      {
          //Initialize the Page Object - SignUpPage.class
          SignUpPage sign_up_page = PageFactory.initElements(driver, SignUpPage.class);
      
          //Call the method - typeEmail(String email) within SignUpPage.class
          sign_up_page.typeEmail("Dmitry");
      }
      

    【讨论】:

    • 嗨@DebanjanB。嗯...我想将 init 移动到单独的类,例如“Base Page”,我们在其中返回“return PageFactory.initElements(driver, pageClass)”,并从每个页面扩展该 BasePage。你能解释一下,为什么在每次测试中初始化它比在例如一次声明中更好。 BasePage,并进一步扩展?
    • 为什么还要一个单独的Base Page?不同的功能应该有不同的模块。一般来说,4 个基本功能可以分布在 4 个模块中,例如Test ClassBrowser FactoryPage ObjectsAssertions 您的 Page Objects 模块将包含所有页面对象。初始化Page Objects 的调用将从Test Class 处理。让我们保持结构简单。
    • "return PageFactory.initElements(driver, pageClass)" 不是最好的想法,因为 Method Chaining 经常将我们推向 StaleElementReferenceException
    • 我不同意在构造函数之外调用PageFactory.initElements 在这种情况下是一种不好的做法。这样您就可以准备好使用 PageObject。在您的示例中,构造函数甚至不会被调用,因为您没有创建 SignUp 页面。
    • @EugeneS 您是否在我的Answer 的上下文中找到PageFactory.initElements outside the constructor is a bad practice?也许,你没看错,the constructor does not even gets called as you don't create a SignUp page。我会根据我的需要一次加载一个single page object,并在Test Execution方面达到最佳性能
    猜你喜欢
    • 2013-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多