• LOGIN
  • No products in the cart.

Login

Retrieve Password
Back to login/register

Implement Maintainable Test Scripts by applying Design Patterns

Implement Maintainable Test Scripts by applying Design Patterns

by Roy de Kleijn

As development teams are able to deliver new features even faster, we also need to find a way to implement test scripts quicker. Design patterns can help with that, as they provide a reusable solution to commonly occurring problems.

What you will learn…

• Advantages of using patterns

• Apply Page Object Model

• Speed-up test script creation

What you should know…

• Java basic syntax

Selenium WebDriver is a great tool to automate almost anything happening within a browser. From simple user actions such as navigating through a website or filling out a form to more advanced actions such as read and write session or local storage, executing JavaScript and the creation of cookies.

It is likely that we will end up with a big amount of automated test scripts. Creating Selenium test scripts can result in an unmaintainable project. One of the reasons can be too much duplicated code is used. Duplicated code can be caused by duplicated functionality and this in turn can result in duplicated use of locators. When this is the case, the code and thus the project will become less maintainable: imagine a locator changes, we now have to walk through the entire test code to adjust the locators where necessary. By using the page object model we can make non-brittle test code and reduce or eliminate duplicated test code. Besides that, use of the page object model improves the readability of the code and allow us to create interactive documentation. Last but not least, we can create automated test scripts using less keystrokes.

Disadvantages:

• Code duplication: while creating automated test scripts we have to repeat a lot of user actions; (for example: login, search)

• Readability: we don’t immediately see what a script does if we see a sequence of Selenium WebDriver commands;

• Synchronization: meaning the test scripts tries to do something while the web element is not there yet;

• Maintainability: the ease of extending the test scripts, how well is the code structured;

• Time spent on creating test scripts: due to the duplication it takes much longer to create test scripts.

The biggest challenge might be to solve those maintainability and brittleness issues, so we can write automated test scripts more easily and maintain them without having false positives. We can do that by applying some kind of design pattern. Today’s software development methodologies enable us to develop new features very frequently and in a short period of time. So we can’t afford duplications and extra time spent on fixing recurring issues. This article describes the usage of the commonly used “Page Object Model” pattern. All examples in this article are based on the website: http://selenium.polteq.com/testshop/index.php.

Page Object Model

Selenium WebDriver – by default – provides two classes LoadableComponent and SlowLoadableComponent to implement the page object model. However, we can simply write our own implementation, so we do not get stuck with the imposed boundaries.

The page object model encapsulates all page specific behaviours to separate classes. The result is that every page gets its own corresponding class containing the modelled user interface for that specific page.

I made a 4 step-plan to implement the page object model. The steps are listed below.

• Define WebElements

• Model the page functionality to the class

• Model the page flow

• Utilize the model to create test scripts

Step 1: Define WebElements

The first step while implementing the page object model might be to identify which elements we like to use in our test scripts. Most of the time it is not required to model all the elements, but just a subset of it can be enough to implement our automated test script. We can create annotated private fields to define those elements. The following example is defining the elements for http://selenium.polteq.com/testshop/index.php?controller=authentication.

Figure 1. Login functionality we are going to model

Listing 1. Define WebElements for the SignInPage

 

public class SignInPage {

private WebDriver driver;

@FindBy(how = How.ID, using = “username-existing”)

private WebElement usernameTextfield;

@FindBy(how = How.ID, using = “password-existing”)

private WebElement passwordTextfield;

@FindBy(how = How.ID, using = “signin_button”)

private WebElement signInButton;

public SignInPage(WebDriver driver) {

this.driver = driver;

PageFactory.initElements(driver, this);

}

}

We defined a couple of private WebElement fields to model the username, password field and the signIn button. In the constructor we instantiate the elements which allows us to perform some action on these elements.

Step 2: Model the page functionality to the class

Now we can create methods that abstract the things a user can see or do on a specific page. It’s a best practise to use sensible names, so we know from the method name what it supposed to do. We can call these methods from our test scripts. Hiding the Selenium details improves the readability from our automated test scripts.

Listing 2. Model functionality

 

public class SignInPage {

private WebDriver driver;

@FindBy(how = How.ID, using = “username-existing”)

private WebElement usernameTextfield;

@FindBy(how = How.ID, using = “password-existing”)

private WebElement passwordTextfield;

@FindBy(how = How.ID, using = “signin_button”)

private WebElement signInButton;

public SignInPage(WebDriver driver) {

this.driver = driver;

PageFactory.initElements(driver, this);

}

public void login(String username, String password) {

usernameTextfield.sendKeys(username);

passwordTextfield.sendKeys(password);

signInButton.click();

}

}

Step 3: Model the page flow

It is likely that we will be redirected to a new page after logging in. This can be modelled by setting a return type to other page objects. This can be useful if we navigate to a different page. We can return the same page object if we don’t navigate to a different page.

Listing 3. Add the flow

 

public class SignInPage {

private WebDriver driver;

@FindBy(how = How.ID, using = “username-existing”)

private WebElement usernameTextfield;

@FindBy(how = How.ID, using = “password-existing”)

private WebElement passwordTextfield;

@FindBy(how = How.ID, using = “signin_button”)

private WebElement signInButton;

public SignInPage(WebDriver driver) {

this.driver = driver;

PageFactory.initElements(driver, this);

}

public SignInPage init() {

driver.get(“http://selenium.polteq.com/testshop/index.php?controller=authentication”);

return this;

}

public MemberPage login(String username, String password) {

usernameTextfield.sendKeys(username);

passwordTextfield.sendKeys(password);

signInButton.click();

return new MemberPage(driver);

}

}

Sometimes the page where we navigate to depends on the page where we are. For example login functionality that occurs on multiple pages. Then we might want to add the class name of the expected page to the method.

Step 4: Utilize the model to create test scripts

Once we have the model in place, we can make use of it when creating test scripts. In previous step we added return types to our methods. Method chaining allows us to invoke several method after each other, on one or different objects. We can make use of content assist in modern IDE’s (Integrated Development Environment). Content assist provides us a list of suggested methods for partially entered strings. In eclipse we can press CTRL + SPACE.

Figure 2. Content assist in Eclipse

Listing 4. Add the flow

 

public class LoginTests {

private WebDriver driver;

@BeforeMethod

public void setUp() {

driver = new FirefoxDriver();

}

@AfterMethod

public void tearDown() {

driver.close();

}

@Test

public void login() {

MemberPage memberPage = new SignInPage(driver).init()

.login(“Test”, “Case”);

Assert.assertTrue(memberPage.isPageDisplayed());

}

}

Some of the methods can return other page objects. This can be useful if we navigate to a different page. We can return the same page object if we don’t navigate to a different page.

Summary

We successfully implemented a basic page object model to increase the maintainability and be able to create automated test scripts even faster. We now have one place with abstraction code and one place with automated test script. On github we can see a full working example and in my book we can see more variants of the page object model implementation.

On the Web

• https://github.com/roydekleijn/webdriver_java_example – Selenium WebDriver Java Example

• http://selenium.polteq.com/ – Tutorials on Selenium webDriver

About the Author

Roy de Kleijn ([email protected]) is a technical test consultant at Polteq where he works with clients on test process and automation, mainly in agile teams, and develops and presents training in Selenium/WebDriver. He is especially interested in web technology, new programming languages and knowledge transfer methods and publishes Selenium-related tutorials at http://selenium.polteq.com and test-related articles at http://rdekleijn.nl. In addition: Roy de Kleijn also wrote a book on Selenium WebDriver, called “Learning Selenium”, http://leanpub.com/LearningSelenium

May 20, 2014

Leave a Reply

Be the First to Comment!

  Subscribe  
Notify of