Java and Selenium: Static methods in Page Objects

2020-04-10 01:23发布

问题:

I'm having trouble with NullPointerExceptions when I try using static methods in a page object. If I do it with non-static methods, it works fine.

Non-static version:

public class ComplaintPage {

    private ExtendedWebDriver driver;

    @FindBy(css = "[data-selector=date-received-complaint]")
    public WebElement dateComplaintReceoved;

    public ComplaintPage() {
        driver = Browser.extendedDriver();
        PageFactory.initElements(driver, this);
    }

    public void setComplaintDate() {
        dateComplaintReceoved.sendKeys(LocalDate.now().toString());
    }
}

Calling code:

ComplaintPage complaintPage = new ComplaintPage;
complaintPage.setComplaintDate();

This works fine. The date field is set.

Static version

public class ComplaintPage {

    private static ExtendedWebDriver driver;

    @FindBy(css = "[data-selector=date-received-complaint]")
    public static WebElement dateComplaintReceoved;

    public ComplaintPage() {
        driver = Browser.extendedDriver();
        PageFactory.initElements(driver, this);
    }

    public void static setComplaintDate() {
*       dateComplaintReceoved.sendKeys(LocalDate.now().toString());
    }
}

Calling code:

ComplaintPage.setComplaintDate();

This does not work, and results in a java.lang.NullPointerException on the line marked with "*" (the line accessing the WebElement).

I kind of like using static methods like this in test, since I don't really see a problem with it, and it makes the code even more easy to read. And I've done it before, in C#/VS, but for some reason I'm missing something important here.

回答1:

NullPointerException is thrown because of how PageFactory works. You see, when you create an instance of ComplaintPage class, you are invoking its constructor:

public ComplaintPage() {
        driver = Browser.extendedDriver();
        PageFactory.initElements(driver, this);
    }

The constructor calls initElements method of PageFactory class. This method initializes all of WebElement and List<WebElement> fields with Java Reflection API. It basically changes the default null values to implementations of the interface. It also provides sort of Lazy instantiation of the WebElement which means - WebElements are found (looked for?) only when needed - when you invoke operations on them.

When you created static methods and static WebElements - you did not call the constructor of the class, which lead to NOT invoking the initElements method.

All of the elements annotated with @FindBy were not initialized. That's why it's not a good idea to use PageFactory with static methods.

Instead of using PageFactory you can just find the element with classic driver.findElement inside the static method.

    public void static setComplaintDate(WebDriver driver) {
        driver.findElement(By.cssSelector("[data-selector=date-received-complaint]")).sendKeys(LocalDate.now().toString());
    }