Improving my WatirMelonCucumber page object framework

I’ve been working on some improvements to my WatirMelonCucumber page object framework, partly inspired by the SpecDriver C# framework I put together, and also inspired by a work colleague who’s especially good at ruby and meta-programming.

Base Page Class to inherit from

The first improvement is adding a base page class that all pages defined inherit stuff from. This means I don’t have to write an initialize for every page, as the base page class initializes each page automagically. This base page class can also navigate to the selected pages direct if needed, check for the appearance of a certain element if needed, and check the title is correctly displayed, again, if needed. Lastly, the base page class catches any methods that are missing and throws these to the browser, which means you can call browser methods such as title, and text at the page level.

class BasePageClass
  include WatirWebDriverHelper

  def initialize browser, visit = false
    @browser = browser
    goto if visit
    expected_element if respond_to? :expected_element
    has_expected_title? if respond_to? :has_expected_title?
  end

  def method_missing sym, *args, &block
    @browser.send sym, *args, &block
  end
end

Watir Page Helper Mixin

I originally saw the Watir Helper idea in Jeff Morgan’s cucumber framework, which I have used here. I have made quite a few changes, not only to support more elements, but also to allow passing in blocks to the helper methods. This helper is included in the base page class, and therefore is accessible in any page defined that inherits from the base page class.

Update: 5th May: See my watir-page-helper gem to include this automatically.

Resulting page model example
The combination of these two improvements mentioned, now mean the actual page classes are nice and neat. For example:

class GoogleHomePage < SearchPageClass

  direct_url "http://www.google.com"
  expected_title "Google"

  button :google_search, :name => "btnG"

  def search_for term
    self.search = term
    google_search
    GoogleResultsPage.new(@browser, false)
  end
end

Ruby & Browser Support

I have changed the framework to use Chrome, since it’s so fast, but that’s easily configurable in env.rb, and watir-webdriver headless instead of Celerity. This means JRuby is not needed, and it can run under Ruby 1.9.2.

Summary

By introducing the base page class, and the watir page helper methods, it means the resulting page models are short, simple and easy to understand. There is a lot less repetition, for example, not including the watir helper in every page, as it’s included in the base, and also not needing an initialize for each page that essentially does the same thing.

Let me know what you think.

Reducing Cucumber page object element duplication using mixins

The one thing that quickly happens when you start using a page object pattern to develop your Cucumber acceptance tests is you end up with duplicate page elements in multiple page objects. This happens because usually your pages often have elements common to every page and it doesn’t make sense defining these more than once, enter page mixins.

Page mixins are methods in ruby that you can mix into a class, so that each method in your mixin is then available in the instance of your class. We can use a mixin to define our common elements which are then available for every class we define.

For example, in our Google/Bing search example, the search text fields are conveniently given the same id in each of the search engine pages, therefore it makes sense to define this once and mix it in to each page.

We create a mixin file which is essentially a module with a bunch of methods. In our case, we define initialize to define our elements, and method missing as this is a common method we use for Browser object delegation.

module PageMixIn
  attr_accessor :search_field

  def initialize *args, &block
    @search_field = self.text_field(:name => "q")
  end

  def method_missing sym, *args, &block
    @browser.send sym, *args, &block
  end
end

We then simply include this mixin into our page class, and the methods are mixed in. The super statement in the class’s initialize method is needed to ensure the instance variables of the mixin are available in the class.

class GoogleHomePage
  include PageMixIn

  attr_accessor :search_field, :google_search_button

  URLS = { :production => "http://www.google.com/" }

  def initialize(browser)
    @browser = browser
    @google_search_button = @browser.button(:name => "btnG")
    super
  end

  def visit
    @browser.goto URLS[:production]
  end

  def search_for term
    self.search_field.set term
    self.google_search_button.click
    google_results_page = GoogleResultsPage.new(@browser)
    google_results_page.results.wait_until_present if WEBDRIVER
    google_results_page
  end
end

This means we eliminate a lot of duplication of page elements, such as the search field, as well as common methods such as the method_missing.

Summary and a quick tip

I have found using page mixins provides a flexible approach to reducing page object element and method duplication. It makes your pages easy to read and compact. A quick tip though: I thoroughly recommend storing all page objects and page mixins under the support directory in Cucumber, as this ensures they are loaded automatically by Cucumber and are consistently available to reference.

Composition or inheritance for delegating page methods?

The thing I like to do when creating a page object pattern for automated web testing is delegating any methods that don’t belong to the Page object itself.

For example, a very simple page object model like this GoogleHomePage doesn’t delegate any methods to the Browser object.

require "rubygems"
require "watir-webdriver"

class GoogleHomePage
  def initialize(browser)
    @browser = browser
  end
  def visit
    @browser.goto "www.google.com"
  end
end

b = Watir::Browser.new :firefox
p = GoogleHomePage.new b
p.visit
puts p.title
p.close

So, the p.title and p.close statements both fail with an error: undefined method `goto' for # (NoMethodError).

One approach would be simply to write appropriate methods for what you would do on the Browser object. For example:

require "rubygems"
require "watir-webdriver"

class GoogleHomePage
  def initialize(browser)
    @browser = browser
  end
  def visit
    @browser.goto "www.google.com"
  end
  def title
    @browser.title
  end
  def close
    @browser.close
  end
end

b = Watir::Browser.new :firefox
p = GoogleHomePage.new b
p.visit
puts p.title
p.close

But this isn’t DRY. It means every method of Browser you access to needs to be rewritten. But I often see this happen.

What we should be doing is simply delegating any methods that don’t exist on the Page object to the Browser object which is passed in at initialization. There are two ways I know of to do this: inheritance delegation and composition.

Inheritance Delegation

Inheritance delegation means changing our class so it delegates appropriately using a DelegateClass. This means anything of class Browser is delegated.

For example:

require "rubygems"
require "watir-webdriver"

class GoogleHomePage < DelegateClass(Watir::Browser) 
  def initialize(browser)
    super(browser)
  end
  def visit
    self.goto "www.google.com"
  end
end

b = Watir::Browser.new :firefox
p = GoogleHomePage.new b
p.visit
puts p.title
p.close

From this point forward you don’t need to refer to @browser, instead you just refer to self in your class.

Composition

Composition is about composing the class of different elements, some of which are passed to the browser. This essentially involves creating a method_missing method and passing these methods to the instance variable @browser.

require "rubygems"
require "watir-webdriver"

class GoogleHomePage
  def initialize(browser)
    @browser = browser
  end
  def method_missing(sym, *args, &block)
    @browser.send sym, *args, &block
  end
  def visit
    @browser.goto "www.google.com"
  end
end

b = Watir::Browser.new :firefox
p = GoogleHomePage.new b
p.visit
puts p.title
p.close

This means that any reference to the Browser object still needs to refer to @browser throughout the class.

Inheritance or Composition?

You can see from the examples above, both approaches are very similar, but from researching these, it seems that most people prefer composition to inheritance in ruby, mainly due to maintainability of class chains. In our example, the inheritance chain is small and very simple, so I don’t think this poses a great maintainability issue.

What do you think? What would you prefer?

Easily manage your rubies with RVM, Bundler and Pik

Background

I’ve spent some time working on setting up an acceptance test framework using Cucumber and ruby under OSX on my ThoughtWorks MacBook Pro as my dev machine.

As a consultant, you can often work on a variety of projects, and these often have different ruby version requirements and use different ruby gems and dependencies. If you don’t use the help of a tool, it quickly becomes difficult to manage these various ruby versions, gems and dependencies.

RVM to the rescue

If you’re using Mac OSX and *-nix platforms, Ruby Version Manager, or RVM, is the tool for you:

“RVM is a command line tool which allows us to easily install, manage and work with multiple ruby environments from interpreters to sets of gems.”

At first, RVM was quite confusing to me, but over a short period of time I have grown to love it. It is *-nix only, but later I will explain what exists in the Windows world that is equivalent (Pik).

Reasons why RVM rocks

  • You can isolate and manage rubies and gemsets in those rubies
  • You associate these rubies and gemsets to projects – using .rvmrc and Gemfile files – so they consistently use the same ruby and gemset
  • It works with Bundler to fetch your ruby gems

RVM Explained in a Diagram

I decided to draw a diagram to explain this, using the really awesome Google docs drawings (goodbye Visio license costs).

RVMExplainedDiagram-AlisterScott
RVM Explained: click for larger view

.rvmrc files

You create one of these in your project root, which specifies which ruby version, and gemset, you want the project to use. When you “cd” into this directory, this is triggered by RVM to do the magic of switching your ruby version – so you’re system thinks you’re running a different version (the first time it asks you if you would like to trust it).

An example .rvmrc file


rvm_install_on_use_flag=1
rvm --create use jruby-1.5.3@celerity

An example message when cd’ing into this dictory


Using /Users/alisterscott/.rvm/gems/jruby-1.5.3 with gemset celerity

The really, really neat thing about this is, if you don’t have that version of ruby, or JRuby, installed then it will automatically fetch it and install it. Neat!

Managing your gems within RVM using Bundler

The second component of RVM that is very neat is gemsets.

A gemset is a collection of gems, that lives in a container that is associated with a version of ruby you have created in RVM: so you can have the same ruby version with various collections or groupings of gems.

Bundler (a gem itself) is used to collect your gems from your specified source – usually rubygems.org, but this can be a local gemserver if set up one in a corporate environment due to proxy issues.

As you’re running RVM with a ruby version and gemset already specified, when you run bundler (bundle install), these gems are inserted into your Gemset container. If you then switch RVMs or gemsets, you would simply rerun “bundle install” to insert the same gems into the different container. This is essentially what happens the first time you run your project on a server, the RVM or the Gemset won’t exist, so you create a script to switch to your correct rvm (using the .rvmrc file), install the bundler gem (because you need this to get the gem bundle), then run a bundle install.

Using RVM and Bundler to bootstrap configuration for running Cucumber features under C.I.

Use can RVM and Bundler to ensure your continous integration server runs your cucumber features correctly. An example shell script to do this on a unix box would be:


rvm rvmrc trust
cd features
cd .. # hack to load RVMRC
set -e
gem install bundler --no-rdoc --no-ri
bundle install
cucumber -p ci

A typical Gemfile


source "http://rubygems.org"
gem "cucumber", "0.10.0"
gem "prawn", "0.8.4"
gem "watir-webdriver", "0.1.8"
gem "celerity", "0.8.7"

I find it is best to specify explicit versions of gems in the GemFile, so you don’t have unexpected  consequences of automatically updating to a newer version of a gem without you knowing.

Gemfile.lock file

When you run bundle install for the first time, a Gemfile.lock directory is created. This contains the entire set of gem dependencies and their known versions that aren’t explicitly specified in your Gemfile (dependencies of your dependencies). This file is important as without it, when you run bundle install, bundler will look for fresh gem depencies, and these could change which could cause all kinds of versioning weirdness. This is why I would encourage people to store this file under version control.

Ruby Versioning on Windows: use Pik

When researching RVM for windows, I came across Pik, a similar concept, but with a little less finesse. Pik lets you have multiple ruby installs on your windows machine, and quickly switch between, or pik, which one you want to use.


C:\>pik switch 191 p129
   == Switching to ruby 1.9.1p129 (2009-05-12 revision 23412) [i386-mingw32] ==

It’s not as cool in the sense it doesn’t get and install your rubies for you, and there doesn’t seem to be same gemset concept, but fortunately Bundler still works the same, and can read your Gemfile.

So the get your ruby environment running on Windows, you could do something like

  1. pik switch 1.8.7
  2. gem install bundler
  3. bundle install

Not quite as neat as RVM, but still pretty neat.

A final note: running Cucumber under JRuby on Windows using Pik

To get coloured output (or non-weird looking output) for Cucumber on Windows under JRuby, you need to use Wac.

  • Download wac and put it on your path (I usually create a c:\bin directory and put this on my path, and put things it in)
  • Run “cucumber | wac” to see proper Cucumber output

Summary

  • RVM is a super neat tool that makes managing multiple ruby versions and gemsets a breeze.
  • There are so many useful scenarios for it, it is hard to describe here, but they include testing, continuous integration and deployment.
  • I find checking in the .rvmrc, Gemfile and Gemfile.lock files into your project ensures consistent reproducible ruby environments across multiple machines.

How to set up Cucumber and Watir on OSX

These are the steps I had to use to get Cucumber and Watir running on OSX. It’s a shame about step 1, it’s a real pain but I don’t know any way around it.

  1. Install Xcode from OSX installation DVD – this takes about 15 minutes
  2. Open a command prompt and use enter the following commands.
  3. sudo gem update --system
  4. sudo gem install rspec --no-rdoc --no-ri
  5. sudo gem install gherkin --no-rdoc --no-ri
  6. sudo gem install cucumber --no-rdoc --no-ri
  7. sudo gem install firewatir --no-rdoc --no-ri

You should be good to go.

Rubular & RubyMine: makes Cucumber easier

I’ve spent the last couple of months establishing Acceptance Test Driven Development on a medium sized software delivery project using Watir & Cucumber.

Cucumber is premised on reading feature files and matching strings to determine what to do, which is done by using regular expressions in step files. This means constant use of ruby regular expressions, and in polishing up on my regular expression skills, I have found rubular incredidly useful. I love the simple layout and the ‘Regex Quick Reference’ at the bottom, just where you need it. It’s very well done.

Rubular: A Ruby regular expression editor and tester
Rubular: A Ruby regular expression editor and tester

The other tool I have found incredibly useful is RubyMine. Up until now, I’ve never really bothered with an IDE for Watir stuff. I’ve mainly stuck to text editors before, but since I have started using Cucumber, I have found the RubyMine tool almost critical, as its support for Cucumber feature files and step definitions is superb. It features click through linking for feature files so you know exactly what step you’re calling, and the debugger is awesome; no more puts statements for me :)

So, if you’re thinking about implementing Cucumber, or using Cucumber but are annoyed with the lack of efficiency in managing a large suite of step definitions, I would thoroughly recommend these two tools. Rubular is free, and I believe RubyMine is about $99, but less if you need multiple licenses. There’s also an Early Access Program where you can use RubyMine for free as long as you’re happy to test it along the way.

Dynamically calling ruby methods in modules

When I am creating Watir tests, I write ruby methods to define user tasks, for example, adding a book to a cart becomes def add_book. I then group these ruby methods into ruby modules divided logically by the area of the application I am writing tests for. For example, I would have a ‘Customer’ module and an ‘Admin’ module for the Depot app. The benefit of using modules is you can avoid namespace conflicts as essentially each method is defined by its module’s prefix. This means that you can happily have def Customer.log_on and def Admin.log_on without any conflict or confusion.

As I have mentioned before, I like defining tests outside my code. These tests ultimately need to execute an associatted ruby method (stored in a module) by passing some data in (and getting an outcome and some output back). One way of calling these tests defined external to our code is to have a massive case statement that determines what calls what. This isn’t ideal as it is a maintenance burden, and really it isn’t needed.

In ruby it’s straightforward to dynamically load ruby modules, and then dynamically call individual methods.

require 'temp'

module_name = "Temp"
method_name = "hello_world"

required_module = Kernel.const_get(module_name)
required_method = required_module.method(method_name)
required_method.call('Alister')

This is all well and good if Temp.helloworld() exists, but if it doesn’t, our code throws exceptions:


`const_get': uninitialized constant Kernel::Temp (NameError)

or

`method': undefined method `hello_world' for class `Module' (NameError)

One way to avoid these exceptions is to wrap the code with a rescue clause, but I realised there are some easy ways to check if both modules and methods exist before loading them.

require 'temp'

module_name = "Temp"
method_name = "hello_world"

if Object.const_defined?(module_name)
  required_module = Kernel.const_get(module_name)
  if required_module.respond_to?(method_name) then
    required_method = required_module.method(method_name)
    required_method.call('Alister')
  else
    puts "Invalid method '#{method_name}' for module '#{module_name}'"
  end  
else
 puts "Invalid module '#{module_name}'"
end

This ensures that the code continues to execute if the module or method name is specified incorrectly, which is sometimes the case if its specified in a spreadsheet, and especially if someone else has designed the spreadsheet.

Once we are happy about dynamically finding methods in modules, the next step is to make sure that each method is called with the correct number of parameters. This property of a method is called the arity.

The great thing about ruby and arity is that you simply determine the number of parameters and then pass in a correct sized array, using a *, and the receiving method will automatically unpack the array into the parameters specified.

puts required_method.arity()
required_method.call(*parameters)

The flexibility that ruby offers is amazing. I have tried to accomplish this same concept in VBScript but I couldn’t work out how. That’s why I am glad Watir uses ruby, it ultimately means my automated test framework is more efficient and maintainable.