The Journey Pattern
25 March 2014, by Chris Arnott
The need for DRY code is a well established idea, which is well explained by Uncle Bob. The Page Object Pattern is the basic application of this principle to web tests. However, it is an idea that does not solve all our problems.
Although it goes some of the way to improving the readbility and extensability of web tests, it still has its issues. For example, people often find that when they start modifying their code, large numbers of their web tests can break, as they are brittle. Locating the source of the problem is also tricky, despite the implementation of the Page Object Pattern.
So are there any better ways to structure web tests that get around this problem?
Antony Marcano, Jan Molak and Kostas Mamalis think so. They gave a presentation at the 5th SDET meetup in London on the Journey pattern. This pattern is an extension of the Page Object Pattern that splits up one Page Object into several parts
as well as moving some of the reusable logic out of the test classes into reusable classes
These parts fit together as shown below:
The are several advantages to splitting up the code in this manner. The separation of concerns about each web page allows the code that is written to be more flexible, and reusable across several tests. You can imagine that one actor class would be able to interact with several different pages on a site.
The code is split at a more abstract level, allowing easier reasoning about the code. When tests do break, the classes where responsibilities lie is easier to reason about, allowing the tests and code to be fixed quickly in the event of a failure. It makes your tests more readable, as shown in the code samples below:
DesiredCapabilites desiredCapabilities= new DesiredCapabilites(); WebDriver driver = new PhantomJSDriver(desiredCapabilities()); driver.get(baseUrl+"owners/find.html"); FindOwnersPage findOwners = PageFactory.initElements(driver, FindOwnersPage.class); OwnersPage owners = findOwners.findWith(EMPTY_SEARCH_TERMS); assertThat(owners.numberOfOwners(), is(10);
Actor theReceptionist = new Actor().with(WebBrowsing.ability(); theReceptionist.attemptsTo( Go.to(findOwnersScreeen.url), Search.forOwnersWith(EMPTY_SEARCH_TERMS), Count.theNumberOfOwners() ); assertThat( theReceptionist.sawThatThe(numberOfOwners()), was(theExpectedNumberOfOwners) );
This pattern is a good extension of the Page Object Pattern. Other patterns have progressed to similar areas, for example the Impersonator Pattern‘s use of actors (personas), but the additional refinement of recognising tasks and abilities as first-class entities results in this pattern being highly flexible.
Why not try it out on your next project and let us know how it improves your testing?