Refactoring page objects The Screenplay Pattern

Preview:

Citation preview

The Screenplay PatternA SOLID alternative

to Page ObjectsAntony Marcano

@AntonyMarcanoriverglide.com

Contributions, quotations & references in:

2

All code is…

SeriouslyHinderedInTesting?

Inspired by Simon Stewart’s opening keynote at Selenium Conf 2016…

Knowledge of programming

All code is…

SeriouslyHinderedInTranslation?

Inspired by Simon Stewart’s opening keynote at Selenium Conf 2016…

Expressing intent

All code is…

SeriouslyHinderedInTransformation?

Inspired by Simon Stewart’s opening keynote at Selenium Conf 2016…

Ease of refactoring

Just enough to give confidencethat the product hangs togetherfor the key usage examples

DON’T try to prove that absolutely everything works together in absolutely every way that the whole product is supposed to

The Screenplay pattern is as a way of separating any kind of interactions with your product, including RESTful APIs, Web or any form of interaction.

For the purposes of this talk, we’re going to focus on page objects…

http://bit.ly/rg-todomvc

Support code using Page Objects

Todo List Page

newTodotodoItemstodosRemainingtoggleAllButtonclearCompletedButtonfilterTodos…

addATodoItem()addTodoItems()toggleAllCompleted()filterItems()…

Responsibilities

How to find page elements

How a user completes given tasks

Let’s go back in time…

“Selenium is not unstable, and your tests don’t need to be flaky. […] When your tests are flaky, do some root cause analysis to understand why they’re flaky. It’s very seldom because you’ve uncovered a bug in the test framework.”-Simon Stewart, Google Testing Blog 2009, “My Selenium Tests Aren't Stable!”

http://bit.ly/rg-pageobject-example

What’s wrong with this?

“A code smell is a surface indication that usually corresponds to a deeper problem in the system. The term was first coined by Kent Beck while helping me with my Refactoring book.” -Martin Fowler

Code Smell: “Large Class”

What can help us refactorto a better design?

SOLIDSingle Responsibility PrincipleOpen Closed PrincipleLiskov Substitution PrincipleInterface Segregation PrincipleDependency Inversion Principle

Let’s focus on…Single Responsibility PrincipleOpen Closed PrincipleLiskov Substitution PrincipleInterface Segregation PrincipleDependency Inversion Principle

Single Responsibility Principle

“If a class has more than one responsibility, then the responsibilities become coupled. Changes to one responsibility may impair or inhibit the class’ ability to meet the others. This kind of coupling leads to fragile designs that break in unexpected ways when changed.” -Robert Martin, Agile Principles, Patterns & Practices

Open Closed PrincipleThe Open Closed Principle (coined by Bertrand Meyer in Object-Oriented Software Construction) states that a class should be open for extension, but closed for modification. This means that it should be possible to extend behaviour by writing a new class without changing existing, working code.

http://bit.ly/rg-todomvc

Todo List Page

newTodotodoItemstodosRemainingtoggleAllButtonclearCompletedButtonfilterTodos…

addATodoItem()addTodoItems()toggleAllCompleted()filterItems()…

Responsibilities

How to find page elements

How a user completes given tasks

Todo List Page

newTodotodoItemstodosRemainingtoggleAllButtonclearCompletedButtonfilterTodos…

addATodoItem()addTodoItems()toggleAllCompleted()filterItems()…

TodoListPagenewTodotodoItemstodosRemainingtoggleAllButtonclearCompletedButtonfilterTodos…

TodoListTasksaddATodoItem()addTodoItems()toggleAllCompleted()filterItems()…

Extract Class

Extract Class

Todo List Page

newTodotodoItemstodosRemainingtoggleAllButtonclearCompletedButtonfilterTodos…

addATodoItem()addTodoItems()toggleAllCompleted()filterItems()…

AddNewTodo

newTodo

addTodoItem ()addTodoItems()

MaintainTodos

toggleAllButtonclearCompletedButton

toggleAllCompleted()clearAllCompletedTodos()

Extract Class

Extract Class

Todo List Page

newTodotodoItemstodosRemainingtoggleAllButtonclearCompletedButtonfilterTodos…

addATodoItem()addTodoItems()toggleAllCompleted()filterItems()…

TodoListPagenewTodotodoItemstodosRemainingtoggleAllButtonclearCompletedButtonfilterTodos…

AddATodoItem

perform()

Extract Class

Replace Method with Method Object

AddTodoItems

perform()

ToggleAllCompleted

perform()

What are we modeling?

Modelling the problem

Not the solution

The Screenplay Pattern

There are actors. Actors have abilities.

Actors perform tasks…

Tasks involve ‘actions’

Things we interact with are just data

Instead of a few large classes,you have more smaller classes.When you identify a new task an actor must perform, just add a new task class.

You don’t have to use cucumber for this either…

Example using Screenplay implementation in Serenity-BDD

Your scenario is a narrative for a cast of actors, each playing a different role. Each actor has the task of performing action to the best of their ability…

The Screenplay Pattern

The Screenplay Pattern

Before you beginDon’t aim to refactor all of your support code.Try an experiment alongside what you have.

See how it feels and if you like it, look at how to use the approach with new scenarios.

In Summary

• As any support code grows, ask first “are we testing too much here?”

• Big classes with interaction methods (like PageObjects) are useful as training wheels

• As we try to go faster, training wheels make us less stable

• The Screenplay Pattern allows us to ride more safely, at speed, from the start

LinksFull article: bit.ly/rg-screenplayExamples on Github: bit.ly/rg-serenity-eg

using Serenity

AcknowledgementsAndy Palmer

John Ferguson Smart & Jan Molak

Contact: antony@riverglide.com http://antonymarcano.com/blog @AntonyMarcano

Materials created with the time, love and attention of Antony Marcano and Andy Palmer

Recommended