Selenium WebDriver: Page Object Pattern and PageFactory

Default admin account

Written by Default admin account Четверг, 23 Февраль 2012

How does it work?
Page Object Pattern is a pattern that displays user interface as a class. In addition to user interface, functionality of the page is also described in this class. This provides a bridge between page and test.

Why should it be used?

Here are the main advantages of Page Object Pattern using:
Simple and clear tests.
Good support of tests, because everything is stored in one place.
Easy creation of new tests. In fact, tests can be created by a person not knowing the features of automation tools.
Simple example of using Page Object Pattern and PageFactory in Selenium WebDriver

So we have the page LoginPage shown on the image above.
This page contains the following elements:
login field
password field
button «LoginButton»
And the following functionality:
to enter something into login field
to enter something into password field
to click on the button «LoginButton»
to log in to the application
So our class describing LoginPage will look the following way:
public class LoginPage {
final WebDriver driver;
@FindBy(how = How.NAME, using = "login")
private WebElement loginEdit;
@FindBy(how = How.NAME, using = "pass")
private WebElement passwordEdit;
@FindBy(how = How.NAME, using = "button")
private WebElement loginButton;
public LoginPage(WebDriver driver) {
this.driver = driver;
}
public void enterLogin(String login) {
loginEdit.clear();
loginEdit.send(login);
}
public void enterPassword(String password) {
loginEdit.clear();
passwordEdit.send(password);
}
public void clickLoginButton() {
loginButton.click();
}
public HomePage login(String login, String password) {
enterLogin(login);
enterPassword(password);
clickLoginButton();
return PageFactory.initElements(driver, HomePage.class);
}
}

Before we’ll examine the above code, let’s look at another HomePage page that we enter after clicking the login button.

This page contains the following elements:
Text «Hello!»
button «ExitButton»
And the following functionality:
Logout
So, our class describing HomePage will look the following way:
public class HomePage {
final WebDriver driver;
@FindBy(how = How.NAME, using = "text")
private WebElement helloText;
@FindBy(how = How.NAME, using = "exit")
private WebElement exitButton;
public HomePage(WebDriver driver) {
this.driver = driver;
}
public void clickExitButton() {
exitButton.click();
}
public LoginPage logout() {
clickExitButton();
return PageFactory.initElements(driver, LoginPage.class);
}
}
Now let’s look at our code:
public class HomePage {
declare a class HomePage
final WebDriver driver;
declare our driver
@FindBy(how = How.NAME, using = "text")
private WebElement helloText;
@FindBy(how = How.NAME, using = "exit")
private WebElement exitButton;
here we use the annotation FindBy for making the WebElement object to know to which element it belongs on web page (for example helloText belongs to the element whose attribute is name = text, and exitButton belongs to the element whose attribute is name = exit)
public HomePage(WebDriver driver) {

constructor of our class must take one WebDriver object
public void clickExitButton() {

public LoginPage logout() {

functionality described above
public LoginPage logout() {

this method returns to us the page class to which we go after a successful logout
clickExitButton();
here we describe the main steps of logout
return PageFactory.initElements(driver, HomePage.class);
and so we return the page class initialized with PageFactory.
The same situation is with LoginPage.
It seems to be easy.
How will our test look?
public class LoginLogoutTest extends TestCase {
WebDriver driver;
private static String login = "admin";
private static String pass = "test";
@Before
public void setUp() throws Exception {
driver = new FirefoxDriver();
}
@Test
public void testLoginLogout() throws Exception {
driver.get("yousite.ru");
LoginPage loginPage = PageFactory.initElements(driver, LoginPage.class);
HomePage homePage = loginPage.login(login, pass);
LoginPage loginPageAfterLogout = homePage.logout();
}
@After
public void tearDown() throws Exception {
driver.quit();
}
}
As we see we’ve got a simple and intuitive description of our test:
LoginPage loginPage = PageFactory.initElements(driver, LoginPage.class);
HomePage homePage = loginPage.login(login, pass);
LoginPage loginPageAfterLogout = homePage.logout();
Why use PageFactory?
For example, in the above classes, we used the following description of the elements on the page:
@FindBy(how = How.NAME, using = "text")
private WebElement helloText;
But as we use PageFactory, code can be written as follows:
private WebElement text;
where text will refer to an element with the attribute name = text
What’s going on?
When we initialize the page using PageFactory, then, if annotation FindBy is not specified, PageFactory searches for elements on the page which name or id attributes match the name of WebElement.
As a result, we actually do not have to worry about searching for elements on the page. If the element will appear on the page, so when we turn to it, it will be initialized.
Also, if we know that element is always present on the page, it is best to use the following declaration:
@FindBy(how = How.NAME, using = "text")
@CacheLookup
private WebElement helloText;
If we don’t do it, then every time when we turn to our element, WebDriver will check if the element is present on the page.

comments powered by Disqus