In all prior Selenium 101 posts, we used rather small and easily contained examples to implement our Selenium test cases. Unfortunately, this does not represent the real world usage that well.

To get better and more maintainable tests we will need to come up with a better structure for our tests. The most commonly used design patterns are the Page Object Model and the in-build Page Factory Pattern. In this post, we will take a look at both.

Page Object Model

By using the Page Object Model you will create a separate class for each page you need to interact with during a test. These objects are then reused in every test case that needs to interact with the specific page. This has a few different advantages:

Code Reuse: You can reuse the page specific class in every test and don’t need to copy and paste any page specific code.Maintainability: If a page changes you only need to apply the necessary changes to one class and not in every test case separately.Readability: By using descriptive names in the page object you get much more readable test cases.

As an example, we will take a simple login page that contains 3 different elements: A username input box, a password field, and a button to submit the login.

1

2

&lt;!DOCTYPE html&gt;

&lt;html&gt;

1

&lt;head&gt;

1

&lt;title&gt;Selenium Academy Design Patter&lt;/title&gt;

1

2

3

&lt;/head&gt;

&lt;body&gt;

1

&lt;form&gt;

1

&lt;div&gt;

1

&lt;h3&gt;Login&lt;/h3&gt;

1

2

&lt;/div&gt;

&lt;div&gt;

1

&lt;input type="text"id="username"&gt;&lt;/input&gt;

1

2

&lt;/div&gt;

&lt;div&gt;

1

&lt;input type="password"id="password"&gt;&lt;/input&gt;

1

2

&lt;/div&gt;

&lt;div&gt;

1

&lt;input type="submit"id="login"value="Login"&gt;&lt;/input&gt;

1

&lt;/div&gt;

1

&lt;/form&gt;

1

&lt;/body&gt;

1

&lt;/html&gt;

To create a test for this page using the Page Object Model we first need to create the necessary class specific to this page. Most likely our test will need to access the username and password fields and, in addition to this, we will need a method to actually submit the login. The page object model ‘LoginPage’ could look like this:

1

2

3

4

5

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

publicclassLoginPage{

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

privatefinalWebDriver driver;

privatefinalBy username=By.id("username");

privatefinalBy password=By.id("password");

privatefinalBy login=By.id("login");

publicLoginPage(WebDriver driver){

this.driver=driver;

}

publicStringGetUsername(){

returndriver.findElement(username).getAttribute("value");

}

publicvoidsetUsername(Stringvalue){

WebElement element=driver.findElement(username);

element.clear();

element.sendKeys(value);

}

publicStringgetPassword(){

returndriver.findElement(password).getAttribute("value");

}

publicvoidsetPassword(Stringvalue){

WebElement element=driver.findElement(password);

element.clear();

element.sendKeys(value);

}

publicvoidsubmitLogin(){

driver.findElement(login).click();

}

1

}

Now we can use this page object in our test case. Please note that here the test case does not need to know any specifics of the login page at all. A test could look like this:

Page Factory

As you have just seen it is possible to implement the page object model without any support from Selenium. Luckily Selenium does offer the possibility to create Page Objects by using the Selenium integrated Page Factory. With the Selenium Page Factory, you can make your page objects even shorter and you will get a performance improvement as Selenium handles most of the heavy lifting.

Let us take a look at how we can modify our Login Page object from above to use the Selenium Page Factory pattern. Please note that with the code below Selenium will cache the lookup of all elements. You would only do this if you are certain that the elements do not change during the lifetime of the page object. On an AJAX-heavy application, you should avoid this and have Selenium lookup the element each time it is accessed.

1

2

3

4

5

6

import org.openqa.selenium.WebElement;

import org.openqa.selenium.support.CacheLookup;

import org.openqa.selenium.support.FindBy;

import org.openqa.selenium.support.How;

publicclassLoginPage{

1

2

3

4

5

6

7

8

9

10

11

12

13

@FindBy(how=How.ID,using="username")

@CacheLookup

privateWebElement username;

@FindBy(how=How.ID,using="password")

@CacheLookup

privateWebElement password;

@FindBy(how=How.ID,using="login")

@CacheLookup

privateWebElement login;

publicStringGetUsername(){

1

returnusername.getAttribute("value");&gt;/pre&gt;

1

2

3

}

publicvoidsetUsername(Stringvalue){

1

2

username.clear();

username.sendKeys(value);

1

2

3

}

publicStringgetPassword(){

1

returnpassword.getAttribute("value");

1

2

3

}

publicvoidsetPassword(Stringvalue){

1

2

password.clear();

password.sendKeys(value);

1

2

3

}

publicvoidsubmitLogin(){

1

login.click();

1

}

1

}

Of course, our test cases will also need a small improvement to properly use the Page Factory: