Yesterday I wrote about creating a simple page object pattern framework in Cucumber that uses Watir to drive browsers.
Ben Biddington left an excellent comment:
“The thing I like about this pattern is you could run the feature against a completely different search engine by just creating a new page object impl.
This prevents the common “step explosion” problem all too common with cucumber suites.”
Ben highlights an important point, the page object pattern decouples your cucumber steps from your GUI, helping to reduce “step explosion”.
To demonstrate this concept, I very easily modified my feature I wrote yesterday to test both Google and Bing, by using the same step definitions, but using scenario outlines instead of scenarios.
Feature: Internet Search
As a casual internet user
I want to find some information about watir, and do a quick conversion
So that I can be knowledgeable being
Scenario Outline: Search for Watir
Given I am on the Home Page
When I search for "Watir"
Then I should see at least results
Scenarios:
| search engine | expected number of |
| Google | 100,000 |
| Bing | 85,000 |
Scenario Outline: Do a unit conversion
Given I am on the Home Page
When I convert 10 cm to inches
Then I should see the conversion result ""
Scenarios:
| search engine | as expected |
| Google | 10 centimeters = 3.93700787 inches |
| Bing | 10 centimetres = 3.937007874 inches |
Scenario Outline: Do a search using data specified externally
Given I am on the Home Page
When I search for a ridiculously small number of results
Then I should see at most 5 results
Scenarios:
| search engine |
| Google |
| Bing |
The way I had written my step definitions before weren’t tied to a particular page (besides the naming, which I simply refactored), so all that was needed was to write two new page.rb files with the same methods as the Google pages.
Bing’s home page:
class BingHomePage
attr_accessor :search_field, :bing_search_button
URLS = { :production => "http://www.bing.com/" }
def initialize(browser)
@browser = browser
@search_field = @browser.text_field(:name => "q")
@bing_search_button = @browser.button(:name => "go")
end
def method_missing(sym, *args, &block)
@browser.send sym, *args, &block
end
def visit
@browser.goto URLS[:production]
end
def search_for term
self.search_field.set term
self.bing_search_button.click
bing_results_page = BingResultsPage.new(browser)
bing_results_page.results.wait_until_present if WEBDRIVER
bing_results_page
end
and, Bing’s results page:
class BingResultsPage
attr_accessor :results, :conversion_result
def initialize(browser)
@browser = browser
@results = @browser.span(:id => "count")
@conversion_result = @browser.span(:class => "sc_bigLine")
end
def method_missing(sym, *args, &block)
@browser.send sym, *args, &block
end
def number_search_results
result = /^[\s\w-]* of ([\d,]+) results$/.match(@results.text)
raise "Could not determine number of search results from: '#{@results.text}'" if not result
result.captures[0].gsub(",","").to_i
end
end
Once I had these pages in place, I didn’t have to require them or anything else, as this is done by Cucumber, so I could now run my cucumber command and get results from two different search engines: Bing and Google. The feature highlighted some subtle differences in how they work: Google had more hits, Bing uses the Australian spelling of centimetres, and adds one more decimal place of precision to conversions.
Summary
As Ben pointed out, and I have demonstrated, by using a page object pattern, you can decouple your steps from your GUI. This allows you to switch GUIs, or indeed testing methods, which in our involved switching search engines, without changing or adding more step definitions, reducing “step explosion”.
Source Code
I have pushed all changes to GitHub: https://github.com/alisterscott/WatirMelonCucumber

Nice posts and nice lightweight framework, Alister! Thank you.
As many other people, we are using very similar approach at Expedia quite for a while. And I really like a nice fit of page objects pattern with cucumber. We have also created some other good small bits in this pattern, e.g. a repo of pages/widgets using Composite and some other design patterns, I hope I will find time to write few posts about it.
Anyway, just wanted to point out – you have too much duplication in your google/bing pages, mate!! :) But I really love how you are gaining one additional level of reusability: not only reusable steps, but the whole scenarios. Coolio.
Thanks for the comment, I look forward to reading about your design patterns.
I have started to show how you can reduce page duplication here: http://watirmelon.com/2011/02/01/reducing-cucumber-page-object-element-duplication-using-mixins/