Avoid fragile webtests by using PageObjects

If you have tried webtesting over some period of time, chances are that you have experienced the fragile nature of webtests. The reason for this fragiltiy is that if there is one part of an application that is bound to change frequently, it is the user interface. So what might be done about the fragile nature of webtests caused by frequent changes to the user inteface?

Use abstraction to reduce the impact of change

If a part of your system is prone to changes you need to isolate that part of the system to reduce the impact of change. This is usually done using some sort of abstraction. An example of this is the use of interfaces in order to be able to change the implementing classes of some exposed functionality without breaking the parts of the system that depend on this exposed functionality. The same way of thinking may be used to make your webtests less fragile. The key to this is to see your web pages as exposing functionality. The search page of google does for example expose the functionality of searching for a term or phrase.

Introducing Page Objects

The functionality of a page can be exposed to your tests using an object, a Page Object, that your tests interact with rather than the actual web page itself. The Page Object is like an interface to your web page. It exposes the functionality on the page while at the same time hiding the implementation details. This means that a test that exercises the search functionality does not know anything about the details required in order to search for something, that is that you need to locate an html element with id “q”, enter text into this, and then press a button with the text “Google Search”. Your tests only know that the page exposes functionality for searching after a phrase.

Abstracting google search functionality using a page object

So how does this look like in real life? Imagine the following test scenario:

Given that I am on the google search page
When searching for the phrase "webdriver"
Then a link to the project's home page should be present in the search results

The test written in JUnit for this scenario using page objects could look like the following

@Test
public void whenSearchingForWebDriverUrlShouldBePresentInSearchResults() {
	SearchPage searchPage = createSearchPage(driver);
	SearchResultPage resultPage = searchPage.searchFor("webdriver");
	assertTrue(resultPage.isLinkPresentInResults("http://code.google.com/p/selenium/"));
}

This test contains only three lines and is easily readable. A test exercising the same functionality but without using page objects is given below:

@Test
public void whenSearchingForWebDriverUrlShouldBePresentInSearchResults() {
	WebDriver webDriver = new FirefoxDriver();
	webDriver.get("http://www.google.com/");
	WebElement searchField = webDriver.findElement(By.name("q"));
	searchField.sendKeys("webdriver");
	searchField.submit();
	assertNotNull(webDriver.findElement(By.xpath(
		"//a[@href='http://code.google.com/p/selenium/']")));
	webDriver.quit();
}

Notice that the test using page objects is much more readable than the one without, and it is easy to capture the essence of the test scenario. Furthermore, imagine having 50 tests that all test various aspects of the search functionality. If the name of the search field changes to “x” all of your tests will break. In order to get them running again you would have to go through each test replacing “q” with “x”. Now, if you used page objects, all your tests would still break, but you would only have to make a change on place, in your page object, instead of all 50 tests.

Key features of Page Objects

The key features of page objects can be summarized as follows:

Methods represent services

The methods represent functionality exposed to the user on the page, such as searchForPhrase(“phrase”).

Hide implementation details

They do not reveal how the functionality is implemented, for example how you locate the search field or the button needed to be pushed in order to perform the search.

Do not make assumptions

Methods on a Page Object are neutral in the sense that they do not state whether something should be true or not. It is up to the users of the Page Object to make assumptions. The Page Objects only provide the ability to make assumptions, such as isLinkPresentInResults(“link”).

Methods return other page objects

This causes the Page Objects to reveal the flow through the application.

Different outcomes are modelled as separate methods

Because the flow of the application is revealed, different paths through the application must be modeled separately. When logging in to an application you would for example expect to be sent to different pages depending on whether you provided valid login credentials or not.

Need not represent an entire page

A Page Object may only represent part of a page, such as a login panel on a portal application that provides personalization.

Succeeding with Webtesting

There are of course other challenges of webtests and this is not the full story of how to succeed with webtesting. For more about the full story have a look at the slides from my presentation Succeeding with webtesting using webdriver at Free-Test 2010

  • http://tattoos4everybody.com flower tattoo designs

    Very interesting site, but you must improve your logo graphics.