Testing a WPF UI using Ruby, Cucumber and WiPFlash.dll

Almost two years ago I blogged about Project
White,
an open source project available on CodePlex which provides
an abstraction on top of the UI Automation library built into WPF and
Silverlight.

Fast forwarding and there is a new project available called WiPFlash which allows you
to drive WPF UI’s for testing purposes created by Liz Keogh who is an
agile\lean coach here in the UK. When I saw this framework, one of the first
advantages such stood out was how clean the API is to work with but also how
lightweight and focused the overal framework was.

This got me thinking… I’ve been presenting on how you can
test ASP.net web applications using Ruby, most recently at QCon London which
was an amazing experience. This got me thinking, if Ruby is a great language
for testing web applications then surely the same applies to desktop
applications. Thankfully, by using WiPFlash together with IronRuby you can have
the same advantage!

One of the questions I’m commonly asked is why would you use
Ruby when testing C# applications? For me, one of the major advantages of Ruby
is it’s readable natural language – this is perfect for tests. As Ruby is a
dynamic language you can also adapt your tests and frameworks to fit your test
domain more effectively. As a result, your tests become more readable and more
maintainable which means they stand much better chance of supporting the
development instead of hindering it. Given the amount of Ruby you need to learn
to get started, there is very little overhead for a project as to get started
you use a very focused subject and grow\learn, as such team members should be
able to pick-up everything required in a hour or so. When combined with
frameworks such as Cucumber you can create really powerful acceptance tests which
can cover large parts of your application with very little implementation.

WiPFlash – Start application and find control

After downloading IronRuby
(currently RC3) and WiPFlash,
you can use the REPL (ir.exe) to interact with your WPF application. For
example:

    require ‘lib\WiPFlash.dll’
    include WiPFlash
    include WiPFlash::Components
    a = ApplicationLauncher.new 
    app = a.launch ‘D:/SourceControl/wipflash/ExampleUIs/bin/Debug/ExampleUIs.exe’

The first line adds a reference to the assembly. We can now
start interacting with the objects. The second\third line includes the namespaces
so we can access the object without including the full namespace. Notice how we
use the Ruby syntax of :: for navigating the namespace – IronRuby will take
care of the translation for us.

The fourth line is where the action starts, we first create
the ApplicationLauncher object, this is part of WiPFlash.dll and is used to
launch the application which is what we do on the fifth line. We now have a
running WPF application along with a reference to the app in the variable. The
application is this example looks like this:

The next stage is to gain access the controls and start
interacting with them as a user might. First, obtain the window where the
controls are. This is very similar to how you would using C#.

    window = app.find_window ‘petShopWindow’

The next stage is to obtain a reference to the actual
control.  This is where C# and IronRuby
go in a slight different direction.  The
C# API uses generics, with the syntax such as:

    TextBox name = window.Find<TextBox>(“petNameInput”)

With IronRuby, we have a slightly different syntax, the most
important part is the of() which defines the generic type:

    name =
window.method(:find).of(TextBox).call(“petNameInput”)

petNameInput refers to the WPF control name, which if you are
unsure of, you can use applications like Snoop
to find the name.

Once we have the control, we can set\get the text property.

    name.Text = “Bob”

Fundamentally, we can now use the API in exactly the same way
we could via C# – but why is that interesting?

Extending WiPFlash via IronRuby

But before we get into the interesting Cucumber + WiPFlash,
we have a problem with the API and the generic syntax. Personally, I think it
is too wordy with the impact facts being lost. Thankfully Ruby is a dynamic
language, and we can extend the framework to meet our requirements resulting in
a syntax of:

    text = window.find_TextBox “petNameInput”

Amazingly, this is easy to achieve thanks to the special
method_missing hook in Ruby. This method is called when a message is sent to an
object which doesn’t match a pre-defined method. This means you can to take
action and is how ActiveRecord allows for a flexible query syntax. 

The code below makes the syntax above possible. GetType takes
in the method name we called, and returns the part relating to a WiP component.
This is converted to a class name within get_class before being used within
find_ui_element together with the args originally passed to the method. Simple,
but effective.

  class WiPFlash::Components::Container
    def get_type(name)
        name.to_s.split(‘_’)[1]
    end

    def get_class(name)
       Kernel.const_get(name)
    end

    def
find_ui_element(class_name, *args)
       self.method(:find).of(class_name).call(args[0][0].to_sym)
    end

    def method_missing(m,
*args, &block)
       ui_type =
get_type m
       ui_class =
get_class ui_type
       find_ui_element(ui_class,
args)
    end
end

With our nice clean API allowing us to obtain controls via
window.find_TextBox(“petNameInput”) we can start testing.

WiPFlash + Cucumber

With this in place, we can now plug everything together and
use Cucumber together with IronRuby to test WPF applications. The complete
example can be found at http://github.com/BenHall/wipflash_cucumber_driven_example

To install Cucumber, run the command (ir being the IronRuby
interpreter):

   ir -S gem install cucumber

For example, let’s say we wanted to test the following:

   Scenario: Saving a product by name only
      Given the application has started
      And I enter the name “Product 1″
      When I save the product
      Then “Product 1″ should be available to purchase 

Above is a cucumber scenario. Using the Given, When, Then
(GWT) syntax we define the ‘given’ steps to setup our test context and data,
‘when’ to perform a particular action and ‘then’ to verify it worked
successfully. The most important aspect is the language used. When defining
your scenario, you should use business oriented language to describe the
behaviour of the application instead of 
the actual implementation or UI. There are two (main) reasons for this,
one is that you can use the scenarios as a communication base with customers
and the business to form acceptance criteria about how the application should
work. The second reason is that if your application’s implementation changes
you only need to change the implementation of the test instead of the wording
and aim. This will save you a huge amount of effort during the project. 

The implementation of the test is as follows. Each cucumber
step relates to a ruby code block:

  Given /^the application has started$/ do
    host = ApplicationLauncher.new
    @app = host.launch Dir.pwd + ‘/src/ExampleUIs/bin/Debug/ExampleUIs.exe’
    @main_window = @app.find_window ‘petShopWindow’
  end
  
  Given /^I enter the name “([^\"]*)”$/ do |product_name|
    textbox = @main_window.find_TextBox “petNameInput”
    textbox.text = product_name
  end
  
  When /^I save the product$/ do
    button = @main_window.find_Button “petSaveButton”
    button.click
    sleep(1)
  end
  
  Then /^”([^\"]*)” should be available to purchase$/ do |product_name|
    combo = @main_window.find_ComboBox “basketInput”
    combo.Items.should include(“Pet[#{product_name}]“)
  end
  
  After do |scenario|
    @app.process.kill
  end  

The main different to what we discussed previous is the
‘After’ step which is a hook within Cucumber called after the scenario has
finished. This means we can kill the application launched in the first step and
ensure we have a clean system with no left over processes.

To execute the tests you would run the command:

   ir -S cucumber features

We can now test our WPF applications using Cucumber, taking
advantage of the flexible nature and 
re-useable steps together with an appropriate language for driving
acceptance tests.

 

About benhall

Ben Hall is a UK C# developer\tester with a strong passion for software development and loves writing code. Ben enjoys exploring different ways of testing software, including both manual and automated testing, focusing on the best ways to test different types of applications. He also loves developing web applications using ASP.net and Ruby on Rails. Ben is an ASP.net MVP and can be contacted by emailing Blog {at} Ben Hall .me .uk
This entry was posted in cucumber, ironruby, ruby, wipflash, wpf. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://agile-and-testing.chriss-baumann.de Christian B.

    Hi there,

    sounds good, and I would really like to have a try, but I´m already failing at line 5, where the app shall be started via the launcher, this is the error message I get:
    “Program.rb:5: can’t convert String into WiPFlash::ApplicationLauncher::FailureToLaunchHandler (TypeError)”

    Any ideas what might cause this? Thx in advance!

    Best Regards,
    Christian

  • http://www.natontesting.com Nat Ritmeyer

    Ben, you may be interested in a gem i’ve written that has been written for use in IronRuby to do UI testing of WPF apps. Take a look here:

    http://www.natontesting.com/2010/07/20/announcing-bewildr-test-your-wpf-ui-apps-with-ironruby/

  • Don Kelly

    I tried this tutorial but couldn’t get the cucumber gem to install. It complains that I don’t have the gherkin gem (the parser). There doesn’t seem to be a way to install the gherkin gem using IronRuby since IronRuby seems to not support native extensions. Any hints?

  • http://neilmosafi.blogspot.com Neil Mosafi

    Very nice. Have done something similar with SpecFlow + White, will check out WiPFlash!