在某些语言(例如Javascript)中,您可以在PageObject内创建Elements的层次结构,例如:

class HomePage {
    loginBox = {
        usernameTextBox = findElement(By.cssSelector("input.login"));
        passwordTextBox = findElement(By.cssSelector("input.password"));
    };
    headerTitle = findElement(By.cssSelector("h1.title"));
}


,然后在测试中,您可以按

function loginTest() {
    homePage = new HomePage();
    homePage.loginBox.usernameTextBox.sendKeys(username);
    homePage.loginBox.passwordTextBox.sendKeys(password);
    homePage.loginBox.loginButton.click();
    assert homePage.headerTitle.contains("Logged In")
}


然而,在Java中,当您尝试使用PageFactory构建内部类时,它似乎并没有陷入内部类中。如果将内部类设置为静态,则可以直接实例化内部类页面对象,但是必须将它们分配给新的对象字段(例如homePageLoginBox = PageFactory.initElements(HomePage.loginBox.class);),这意味着必须显式实例化每个内部类。

Page Factory是否有办法一次创建一个分层的页面结构,并实例化和访问这样一个有组织的Page Object(包括所有细分)?

评论

您是否尝试过重载类实例化方法,并在父实例上包含子类实例?

@mutt我最终明确地初始化了内部类。我不认为pageFactory.initElements()执行构造函数,对吗?无论如何,您都必须以某种方式将驱动程序对象传递给它们...

是的,这就是为什么我提到超载。您基本上可以重新编写initElements()并允许它传递到驱动程序中,以便您可以针对现有实例实例化它们,而不是新实例化。

PageFactory并不是页面对象的实现。在我当前的项目中,我们只是使用充满定位器的嵌套静态类,以及将它们作为参数的辅助方法。不仅省去了无需实例化的麻烦,而且还大大减少了StaleElementExceptions。

#1 楼

继承很快就会变得混乱,您可以尝试使用合成来代替使用继承来做一件事。将嵌套的页面对象创建为完整的顶级类,然后将它们作为要访问的实例字段放入代码中。

// It's own file
public class MyPage {
    private final WebDriver driver;

    // Nest your "inner" class through composition instead of inheritance
    public final LoginBoxPage loginBox;

    public MyPage(WebDriver driver) {
        this.driver = driver;
        loginBox = new LoginBoxPage(driver);
}

// It's own file
public class LoginBoxPage {
    private final WebDriver driver;
    private final By username = By.css(...);
    private final By password = By.css(...);
    private final By submitButton = By.css(...);

    public LoginBoxPage(WebDriver driver) {
        this.driver = driver;
    }

    public LoginBoxPage username(String user) {
        driver.findElement(this.username).sendKeys(user);
        return this;
    }

    public LoginBoxPage password(String pw) {
        driver.findElement(this.password).sendKeys(pw);
        return this;
    }

    public void submit() {
        driver.findElement(submitButton).click();
    }
}


此特定示例可以像下面这样使用:

public void test() {
     WebDriver driver = new ChromeDriver();
     MyPage myPage = new MyPage(driver);

     // utilizing fluent returns
     myPage.loginBox.username("herp").password("derp").submit();

     // or not
     myPage.loginBox.username("herp");
     myPage.loginBox.password("derp");         
     myPage.loginBox.submit();
}


评论


我认为,使页面对象不可变,可以减少副作用,从而极大地提高了长期可维护性。如果您有公共实例字段,请将其保留为最终值可确保您的分配不会被浪费。我将它们公开,以使其更接近您对javascript的熟悉,但是通常我会将带有吸气剂的组合式内部页面对象设为私有,以进一步推动家庭不变性。

–朱利安
17年8月25日在18:22

在您的示例中,您没有像homePageLoginBox = PageFactory.initElements(HomePage.loginBox.class); ...那样使用pageFactory。

– 1234
18年7月25日在22:48



@Studeera不,您什么都没有丢失。当我写这篇文章时,我不知道PageObject是一个特定的实现,因为我从未使用过它。因此,我认为该主题更广泛地讨论了页面对象模型。后见之明。我不知道如何使用PageFactory实现将它们放在一起。

–朱利安
18年8月15日在20:04