TLDR; Mix and match different abstraction layers and Objects to create the architecture you need to support your automated execution activities to support clarity and ease of development.

I found a postit note on my desk. I can’t remember when I drew it but it seems to have been an attempt to group different levels of abstractions used when automating, in this case automating a Web GUI.

Notionally I think of this as moving from left to right from “most logical” to “most physical” where “most” simply means “from the abstractions used” rather than “the most physical representation possible”.

<a name=“more”></a>

An example of a Domain level abstraction could be a User.

I might write an @Test with at a User level of abstraction.

@Testpublic void userCanAmendTheirPassword(){ User user = new User("bob","dobbs").canUseWeb(driver); user.login().and().changePassword("newpassword"); user.logout(); user = new User("bob","newpassword").canUseWeb(driver); user.login();}

I might use a User level of abstraction to setup state which I drop to a ‘lower’ level of abstraction to assert on.

@Testpublic void userCanNotLoginWithIncorrectPassword(){ User user = new User("bob","wrongpassword").canUseWeb(driver); user.login(); LoginPage loginPage = new LoginPage(driver); Assert.assertEquals("Wrong username or password",             loginPage.getErrorMessage());}

Note: I typed the above code straight into evernote, it isn’t ‘real’ code, the abstractions it uses do not exist (they are uber logical).

Abstraction Levels Offer Restrictions

Each level of abstraction restricts what can be done.

e.g.

  • At a User level we can’t fill in the username and tab to the password, leave it blank and then tab to the login button and press enter.
    • If we want to automate at that level then we would drop down to an Elements or WebDriver level.
  • Possibly we could not create a User with a blank "" password, the User might enforce domain rules to prevent us making mistakes in the automation.
    • If we want to automate at that level we might need to use Data Entities (which might lack the same level of field value enforcement), or go direct to Page Objects.

Having a User level restricts what we can do at that level so @Test methods written using the User level are clearer in terms of intent at that level.

Each level of abstraction limits what we can do, but offers clarity and more specificity because of it.

Abstraction Layers Build on Each Other

A User ‘login’ method could be implemented using direct Driver calls e.g. driver.findElement(By.id("loginname")).sendKeys("bob")or could be built using a Workflow or an Action.

e.g. new LoginUserAction(driver).login("bob","dobbs");

A person coding at the Domain level abstraction should not have to care how it was implemented, they would only know that a User can login.

If they do care how it was implemented then they would write code with using level of abstraction that represents their concerns.

You Don’t Need All the Abstractions

This diagram is not intended to say “You need to build a 7 level abstraction model where each level builds on the next”. It is a logical model designed to represent concepts.

I don’t think I have ever worked on a project where we automated a Web GUI which used all these abstractions.

I have worked on projects using:

  • Users
  • Workflows
  • Navigation
  • Page Objects
  • Driver

And other projects using:

  • Navigation
  • Page Objects
  • Components
  • Elements
  • Driver

And others using:

  • Data Entities
  • Page Objects
  • Driver

Mix and match to create the architecture you need to support your automated execution activities.

Use Abstractions for Clarity

Build @Test code which makes your code:

  • readable
  • easy to develop
  • easy to maintain
  • robust in the face of application changes
  • etc.

See also:

“Being abstract is something profoundly different from being vague … The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise.” Edsger W. Dijkstra

And now I can finally tidy my desk and put that postit note in the bin.