You are on page 1of 28

!!

T9
Test!Automation!

10/16/2014!11:15:00!AM!

Automation Abstractions:

Page Objects and Beyond


!

Presented by:

Alan Richardson
Compendium Developments

Brought(to(you(by:(
(

(
(
340!Corporate!Way,!Suite!300,!Orange!Park,!FL!32073!
888G268G8770!H!904G278G0524!H!sqeinfo@sqe.com!H!www.sqe.com!

!
Alan Richardson

Compendium Developments
Alan Richardson has more than twenty years of professional IT experience,
working as a programmer and at every level of the testing hierarchyfrom tester
through head of testing. Author of the books Selenium Simplified and Java For
Testers, Alan also has created online training courses to help people learn
technical web testing and Selenium WebDriver with Java. He now works as an
independent consultant, helping companies improve their use of automation,
agile, and exploratory technical testing. Alan posts his writing and training videos
on SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, and
CompendiumDev.co.uk.
Automation Abstractions:
Page Objects and Beyond

Alan Richardson
@eviltester

www.SeleniumSimplified.com
www.EvilTester.com
www.CompendiumDev.co.uk
www.JavaForTesters.com

When you start writing automation for your projects, you quickly realize that you need to organize
and design the code.

You will write far more than test code; you also will write abstraction code because you want to
make tests easier to read and maintain.

But how do you design all this code? How do you organize and structure it?

Should you use a domain specific language?

Should you go keyword driven or use Gherkin?

Should you use page objects with POJO or Factories?

Do you create DOM level abstractions?

Where do domain models fit in?

Alan Richardson provides an overview of options available to you when modeling abstraction layers.
Based on his experience with many approaches on real-world commercial projects, Alan helps you
understand how to think about the modeling of abstraction layers.

Illustrated with a number of code examples, Alan shows you a variety of approaches and discusses
the pros and cons associated with each.

https://xp-dev.com/svn/AutomationAbstractions
2
What is Abstraction?

Modelling

Separation of concerns

Logical vs Physical

Functional vs Structural

Interfaces vs Implementations

Data / Entities / Persistence

Functionality / Task Flow

Goals / Strategies

Layers GUI, DB, HTTP
3

Etc.

I must create a system. or be


enslav'd by another Mans; I
will not reason & compare:
my business is to create
William Blake, 1820
Jerusalem: The Emanation of the Giant Albion
4
http://www.blakearchive.org/exist/blake/archive/object.xq?objectid=jerusalem.e.illbk.10&java=no
Example Test Without
Abstraction
@Before
public void startDriver(){
driver = new FirefoxDriver();
}
@Test
public void canCreateAToDoWithNoAbstraction(){
driver.get("http://todomvc.com/architecture-examples/backbone/");

int originalNumberOfTodos = driver.findElements(


By.cssSelector("ul#todo-list li")).size();

WebElement createTodo = driver.findElement(By.id("new-todo"));


createTodo.click();
createTodo.sendKeys("new task");
createTodo.sendKeys(Keys.ENTER);

assertThat(driver.findElement(
By.id("filters")).isDisplayed(), is(true));

int newToDos = driver.findElements(


By.cssSelector("ul#todo-list li")).size();
assertThat(newToDos, greaterThan(originalNumberOfTodos));
}
@After
public void stopDriver(){
driver.close();
driver.quit(); NoAbstractionTest.java 5

Example Test Without But this does use some


Abstraction abstraction layers
@Before
public void startDriver(){ Firefox Browser Abstraction
driver = new FirefoxDriver();
}
WebDriver Generic Browser Abstraction
@Test
public void canCreateAToDoWithNoAbstraction(){
driver.get("http://todomvc.com/architecture-examples/backbone/");
Locator
LocatorAbstractions
Abstraction
int originalNumberOfTodos = driver.findElements(
By.cssSelector("ul#todo-list li")).size();

WebElement createTodo = driver.findElement(By.id("new-todo"));


createTodo.click();
createTodo.sendKeys("new task");
createTodo.sendKeys(Keys.ENTER); WebElement Generic Element Abstraction

assertThat(driver.findElement(
By.id("filters")).isDisplayed(), is(true));

int newToDos = driver.findElements( Manipulation Abstractions


By.cssSelector("ul#todo-list li")).size();
assertThat(newToDos, greaterThan(originalNumberOfTodos));
}
@After
public void stopDriver(){
driver.close();
driver.quit(); NoAbstractionTest.java 6

}
WebDriver provides abstractions

Browser

DOM

Web Element

Tool vendors gain value from generic abstractions.

You gain value from 'domain' abstractions.

Example Test With Abstraction


@Before
public void startDriver(){
driver = new FirefoxDriver();
}

@Test
public void canCreateAToDoWithAbstraction(){
TodoMVCUser user =
new TodoMVCUser(driver, new TodoMVCSite());

user.opensApplication().and().createNewToDo("new task");

ApplicationPageFunctional page =
new ApplicationPageFunctional(driver,
new TodoMVCSite());

assertThat(page.getCountOfTodoDoItems(), is(1));
assertThat(page.isFooterVisible(), is(true));
}
@After
public void stopDriver(){
driver.close();
driver.quit(); NoAbstractionTest.java 8
}
Why Abstraction?

Change implementations

Single Responsibility only changes when


necessary

Makes automation readable and maintainable

We can unit test some of our test code

etc.

Some Abstraction Layer Categories


1) Data
Generic Data Abstractions e.g. email, postcode
2) Physical
Physical layout of your application e.g. pages,
components
Navigation across pages
3) Domain
Your application Entities domain e.g. user, account
4) Logical
User actions, workflows
10
Common Automation Abstractions

Page Objects: pages, components, widgets

Dom Element Abstractions: select, textbox, etc.

Domain Objects: user, account, order

Gherkin (Given/When/And/Then)

Domain Specific Languages: code, keywords

...

11
Abstraction != Implementation

Abstraction != Tool / Framework /


Implementation

Gherkin != Cucumber

Page Object != Page Factory / Slow Loadable

DSL != Keyword Driven

If we want to get good at abstraction then we


need to model, split apart, make the relationships
clear, and be aware of our options.
13
A Page Object abstracts a Page

Often has methods for


Opening the page
Accessing elements
Doing stuff, and navigating as a side-effect
Logical high level functionality e.g. login
Low level physical functionality e.g.
typeUsername, clickLoginButton

Should a Page Object be responsible for all of


this? 15

Page Object Design Decisions

What methods does it have?


Functional

login(username, password),

loginAs(user)
Structural

enterName(username), enterPassword(password),
clickLogin(), submitLoginForm(username, password)

Does it expose elements or not?


public WebElement loginButton;
public WebElement getLoginButton();
public clickLoginButton();
16
Page Object Functionality
Approaches

Expose WebElements Directly


Leads to WebElement Abstractions
public WebElement userNameField;

Hide WebElements behind physical functional


methods e.g. typeUserName("bob");

Logical helper methods e.g.


loginAs(name,pass)

Layers of Page Objects


Physical
17
Logical

Navigation Design Decisions

Does a Page Object return other pages?


public IssueListPage submit(){
driver.findElement(By.id(submit)).click();
return new IssueListPage(driver);
}

Or Navigate implicitly after interactions

Or have navigation objects

18
Implicit or Explicit Wait?

Implicit Wait
driver.manage().timeouts().
implicitlyWait(15L, TimeUnit.SECONDS);

assertThat(driver.findElement(
By.id("filters")).isDisplayed()
, is(true));

Explicit Wait
driver.manage().timeouts().
implicitlyWait(0L, TimeUnit.SECONDS);

WebDriverWait wait = new WebDriverWait(driver,15);

wait.until(ExpectedConditions.elementToBeClickable
(By.id("filters"))); 19
Example: 'NoAbstractionTest.java'

Implementing Page Objects



POJO
Plain object, driver in constructor, methods use
driver.<method>

Page Factory
Annotated elements, lazy instantiation via reflection

LoadableComponent
Common interface (load, isLoaded), isLoaded
throws Error

SlowLoadableComponent
Common interface, waits for on isLoaded

Other approaches? 20
Example Implementations

21

POJO

'ApplicationPage.java'
Used in 'SequentialCreationOfTest.java'
Not much refactoring in the example

Simple Class

WebDriver passed to constructor

Composition of any components

e.g.
com.seleniumsimplified.todomvc.page.pojo
'ApplicationPage.java'

Not much refactoring in the example 22
Functional vs Structural

Functional
loginAs(username, password)

Structural
enterUsername
enterPassword
clickLoginButton
submitLoginForm(username, password)

24
Functional Vs Structural Example

One way of answering what methods to put on


a page object
Is it functional / behavioural?
Is it structural / Physical?

Functional 'uses' Structural implementation

Why?
Sometimes it is just a naming difference
Handling exceptions in functional but not structural
Higher level methods in Functional
Different concepts e.g. deleteLastItem
25

Page Factory

Annotate fields with @FindBy

Instantiate in constructor using


PageFactory.initElements
Can create your own page factory initialiser

Avoids boilerplate accessor methods

Fast to create Page Objects

Might become harder to expand and maintain

26
Page Factory Example
@FindBy(how = How.CSS, using="#todo-count strong")
private WebElement countElementStrong;

@FindBy(how = How.CSS, using="#todo-count")


private WebElement countElement;

@FindBy(how = How.CSS, using="#filters li a")


List<WebElement> filters;

@FindBy(how = How.ID, using="clear-completed")


List<WebElement> clearCompletedAsList;

@FindBy(how = How.ID, using="clear-completed")


WebElement clearCompletedButton;

public ApplicationPageStructuralFactory(WebDriver driver, TodoMVCSite todoMVCSite) {

PageFactory.initElements(driver, this);

this.driver = driver;
27
...

SlowLoadableComponent

Some pages and components need


synchronisation to wait till they are ready
One approach SlowLoadableComponent adds
responsibility for waiting, to the page
extend SlowLoadableComponent

Standard interface for synchronisation on load


get()

If isLoaded then return this Else load

While not loaded{ wait for 200 millseconds}
Implement load and isLoaded
28
Fluent Page Objects
todoMVC = new ApplicationPageFunctionalFluent(
driver, todoMVCSite);
todoMVC.get();

todoMVC.enterNewToDo("First Completed Item").


and().
toggleCompletionOfLastItem().
then().
enterNewToDo("Still to do this").
and().
enterNewToDo("Still to do this too").
then().
filterOnCompleted();

29

Fluent Page Objects



Methods return the page object or other objects
instead of void
void clickDeleteButton();
PageObject clickDeleteButton();

Syntactic sugar methods:
and(), then(), also()

Can work well at high levels of abstraction and
when no navigation involved

Train Wreck?

30
Navigation Options

Direct in Test: page.get(); page.waitFor();

Instantiate new pages based on test flow


Navigation as side-effect, may have to bypass 'get'
Loadable pages, non-loadable, support classes

Page Object methods might return other Pages


e.g. a method on the login page might be

MyAccountPage clickLogin();

We might use navigation objects


direct, Jump.to(MyAccountPage.class)
path based (current page desired page)

Navigate.to(MyAccountPage.class) 31
Page Objects & Domain Objects

Instead of
todoMVC.enterNewToDo(New Item)

We could have have


ToDoItem newItem = new ToDoItem(New Item);
todoMVC.enterNewToDo(newItem);

See code in DomainBasedTest

33

Domain Objects That Span Logical


& Physical
e.g. User

user.createNewToDo(new item)

user.createNewToDo(newItem)

See use in NoAbstractionTest

34
Sometimes it is possible to over
think this stuff

Don't let thinking about this slow you down

Conduct experiments

Refactor

Rethink if
you are maintaining too much
your abstraction layer stops you doing stuff
you are 'working around' your abstraction layers

35

Element
Abstractions

36
Element Abstraction Example
public interface Checkbox {
public boolean isChecked();
public Checkbox check();
public Checkbox uncheck();
public Checkbox toggle();
}

Would you include 'toggle'?

37

Element Abstractions

Existing support classes: Select,

Possible: TextBox, Checkbox, TextBox, File etc.

Can enforce Semantics


Checkbox: isChecked, check(), uncheck(), toggle()
TextBox: clear(), enterText()
etc.

Pass back from Page Objects into test?

38
Element Abstraction Pros and Cons

May have to create a custom page factory

Can help 'restrict' code i.e. check or uncheck,


rather than click, enforces 'semantics'

If you create them...


allow return WebElement

so that I can go beyond the abstraction layer if I need to.
Not required if it is just a WebElement wrapper.

39

Component Abstractions

Shared Components/Widgets on the page

e.g.
VisibleToDoEntry, VisibleToDoList
Filters, Footer, Header, etc.

Could have 'functional' representation for


repeated items e.g. login forms

Could have 'structural' representation

Likely use : page object composition

40
Component Abstraction Example

TodoEntry todo = page.getToDoEntryAt(lastItemPosition);

todo.markCompleted();

Instead of

page.markTodoCompleted(lastItemPosition);

41

Gherkin as an abstraction layer


Feature: We can create and edit To Do lists in ToDoMvc

We want to amend todos in ToDoMVC because that is


the set of exercises on the abstraction tutorial

Scenario: Create a ToDo Item


Given a user opens a blank ToDoMVC page
When the user creates a todo "new task"
Then they see 1 todo item on the page

Implement steps using highest appropriate


abstraction layer

CucumberJVM as 'DSL implementor'

'Expressibility' vs 'Step Re-use'

See todomvc.feature and ToDoMvcSteps 42


My modeling biases

Driver
Inject so instantiate any page or component as
required/desired at any time

Explicit Synchronisation
To make sure that the desired object is available
and ready for use (as defined by synchronisation)

Navigation
Implicit (via taking action e.g. click)
Explicit Navigation Object, not in page object

Open/jump (via driver.get)

To (state model from current, to desired) 43

My modeling biases

Page Objects
Physical

abstract the 'real world'
Components

For common features on the page
Logical

abstract the functionality

Sometimes these are entity methods not page objects
e.g. user.registers().and().logsin()

I tend not to....


abstract WebElements 44
My modeling biases

I tend not to....


abstract WebElements
Use inheritence to create a model of the app

e.g. MyAppPage extends GenericAppPage
Use 3rd party abstractions on top of WebDriver

45
Are there rights and wrongs?

Right / Wrong?

Decisions?

Project/Team/Organisation Standards?

Identify your own biases -


Experiment
Recognise your decisions
47

Decisions

The 'limits' and overlap of Abstraction Layers

Build it now, or 'refactor to' later

How much change is anticipated?


To which layer? GUI, Business domain, Workflow?

Who is working with the automation code?


Skill levels? Support needed?

How/When with the automation execute?

48
To the creative mind there is
no right or wrong. Every
action is an experiment, and
every experiment yields its
fruit in knowledge.
The Illuminatus Trilogy
Robert Anton Wilson
49

Other Useful Links

Jeff Cheezy Morgan page-object ruby gem,


data_magic gem and stareast code
https://github.com/cheezy?tab=repositories

Marcus Merrell
Self-Generating Test Artifacts for Selenium/WebDriver
https://www.youtube.com/watch?v=mSCFsUOgPpw

Anand Ramdeo
One Step at a Time
https://www.youtube.com/watch?v=dFPgzH_XP1I

50
Homework

Using the code at


https://xp-dev.com/svn/AutomationAbstractions/
Compare the different implementations under 'main'

com.seleniumsimplified.todomvc.page
Investigate how the Page Objects delegate to each
other, and the Domain Objects use Page Objects
Examine the 'test' usage of the Page Objects and
Domain Objects
Examine the different navigation approaches

52

You might also like