Watir, Selenium & WebDriver

Please also see my new ‘Watir-WebDriver: a detailed introduction‘ post.

Background

Of all the open source automated web testing tools available, Watir and Selenium have been the two most popular ones. Traditionally there has been advantages and disadvantages of each. Selenium’s most useful features have been its support for multiple programming languages, and is support for testing a wide variety of browsers. This is because Selenium uses JavaScript to interact with the browser, and all modern browsers support JavaScript.

Watir

Watir was originally designed to support Internet Explorer only, and was originally designed as a ruby library, meaning you had to use ruby. Watir’s most useful feature was, and is, its neat API, most likely that way because it was designed by testers. Also Watir has been traditionally had more functionality than Selenium, because it was designed to interact directly with IE instead of using JavaScript, as there are limits to what you can do with JavaScript, ie. you can’t script uploading a file.

The limitations of Watir have been addressed over time, for example, by creating new versions that support other browsers (FireWatir, SafariWatir and ChromeWatir for example), but the task of porting Watir to a new browser isn’t an easy one, and the task of keeping every port of Watir in sync, with the same API, is difficult. Because of Watir’s power, there has been lots of interest in it as a tool, particularly from developers who use other languages. Understandably, they have wanted to use the language they are accustomed to, and use for production code, and hence numerous language ports of Watir have also been created: Watij and WatiN to name two.

Selenium & WebDriver

Selenium has had its challenges also. Whilst it has traditionally been flexible in language choice, it has technical limitations because of its JavaScript architecture. It also hasn’t offered a way to control a headless browser. Late last year WebDriver was announced. WebDriver is a common browser automation tool that uses what ever is the most appropriate mechanism to control a browser, but with a common API. WebDriver supports not only real browsers (IE, Chrome & Firefox) but also headless ones (using HtmlUnit). Watir uses have had access to a headless browser by using Celerity. WebDriver was quickly merged with Selenium, to become Selenium 2.0.

Watir & WebDriver

So, what does WebDriver mean to Watir? Some people in the Watir project see an opportunity to leverage the effort put into WebDriver, but to continue to offer the clean neat API that Watir does. Jari Bakken has released an early version of Watir-WebDriver, essentially Watir’s ruby API utilising the WebDriver engine. By using WebDriver, Watir can support any browser that WebDriver does, including a headless HtmlUnit browser, without using Celerity.

What does this mean for the future of Watir?

If you’re a Watir user, it doesn’t really make that much difference. If you think of automated web testing as a car, Watir is the steering wheel and dashboard, which interact with the engine. Allowing Watir users to use WebDriver is like providing an additional engine choice, but keeping the steering wheel and dash the same.

Ultimately, I think that Watir will remain a very popular automated web testing tool, one that has been designed by testers for testers. I can see the usage of WatiN and Watij reducing as more developers move to Selenium 2.0/WebDriver which will offer the same functionality as Watir using a different API and multiple programming languages. If WebDriver can focus on the detail of controlling browsers, ultimately Watir will be a better tool as more effort can be spent on improving the Watir API, upgrading the steering wheel and dash, so to speak.

AWTA 2009 survey results

I conducted a survey for the Austin Workshop on Test Automation (AWTA) to see what people thought was good about the workshop and what could be improved in the future.  The response was very positive.

Whilst there were twenty-one questions, I believe the following two graphs tell the story:

How much fun did you have at AWTA 2009?

How much fun did you have at AWTA 2009?

Would you attend another AWTA?

Would you attend another AWTA?

The full results are available here. Bret also did a nice writeup of the AWTA 2009 proceedings here.

FireWatir 1.2.1 on Ubuntu 8.04

I have to admit I hadn’t used FireWatir up until this afternoon. I haven’t really had a need and I have had some hesitation due to the separate code repositories.

Bret Pettichord announced recently FireWatir 1.2.1 where FireWatir has been reintegrated with (vanilla) Watir.

I have been meaning to try a flavour of Watir on my new favourite operating system for some time, so I thought this afternoon was an ideal time. I created a fresh Ubuntu 8.04 VirtualBox machine to use.

Running the FireWatir unit tests

Running the FireWatir unit tests

Overall I am very impressed. The tests ran a bit slow, especially entering text into text boxes. I had to run a lot of commands using sudo. I’m not sure if it should be this way.

I documented the steps taken to get FireWatir up and running on a fresh Ubuntu image. I also have transferred all the content from the old FireWatir wiki to the Watir wiki now that it has been reintegrated.

I also recorded the results of the unit-tests. I will follow up the few failures when I get time.

Update: Bret pointed out two of the failures were due to pop-up blocking. Fixed now and reran: new results.

Running watir tests from a confluence wiki page

Background Information

Defining test cases in a wiki has many benefits:

  • It’s easy to write, read and update;
  • It’s centrally located and easily accessible;
  • There’s in-built version control.

I know that FitNesse/Faucets is a wiki built for this purpose, but I have used it before and have a few issues with it:

  • It defines the test scripts in wiki tables which means it’s difficult to write logic;
  • The FitNesse wiki functionality is basic compared to other wiki software available;
  • I couldn’t find a way to store the historical results of test runs; and
  • Most organisations already have a enterprise wiki in place so having another wiki is duplicating effort.

Its just as easy to use your enterprise wiki and its API to run your Watir tests, and then write back the results (but that’s another post).

My favourite enterprise wiki software is Confluence, not just because it’s a rock solid product but also because I love Atlassian’s philosophies. This includes providing the software to open source projects, such as Watir, and also providing free personal licenses which I have used to provide this example.

Writing Watir tests

I have already discussed how I usually organise my Watir tests. In this example I am using three methods I have already written for the Depot Rails Application.

Customer.add_book(bookTitle)
Customer.check_out(customerName, customerEmail, customerAddress, customerPaymentMethod)
Customer.empty_cart()

The full code for each method is at the bottom of this post.

Defining test cases in Confluence

I have created a very basic wiki page that defines some test cases in wiki tables. In this example I have three different tests, but in reality I would have more permutations in each table. (Click image for large version)

Confluence Wiki Page with Watir Tests Defined

Note that each test case has a Function, Test and test data associated with it. The reason the test data is on the right hand side of the tables is to support varying amounts of test data for various test cases. Also note that the table supports both positive tests and negative test cases (testing for errors).

Another benefit of using a wiki page is that you can easily add additional information. For example, you may have a manual verification step at the end of your tests that you can also document in the same wiki page: it needn’t be in a different place. You can even insert pictures and attachements.

Writing a basic script to run Watir tests defined in Confluence

After a wiki page has been created it’s a matter of writing some ruby code to parse the page and run the tests. Fortunately there is already an excellent ruby library already written for this purpose: Confluence4r.

So really it is just a matter of reading each line in the wiki page and looking for a line that is a table row (not a header), determining which ruby method to run and running it.


require 'watir'
require './confluence4r.rb' # for wiki
require './Customer.rb'
require './Common.rb'

server = Confluence::Server.new('http://localhost:8080')
server.login('admin', 'password')
wiki_page = server.getPage("Watir","WatirMelon")
page_content = wiki_page['content']
page_content.each do |line|
    if line =~ /^\|{1}[^\|]/ then # if line begins with a | then we have an executable test.
        begin
        line.strip! # remove newline markers.
        cells = line[1..-1].split('|') #split line by | excluding first character.
        raise 'Not enough parameters.' if cells.length < 4
        cells.each { |cell| cell.strip! }
        module_name = cells[0]
        method_name = cells[1].downcase.strip.sub(' ','_') # automatically determine function name based upon method name.
        comments = cells[2]
        expected_outcome = cells[3]
        expected_error = cells[4]
        parameters = cells[5..-1] # the remaining cells.
        required_module = Kernel.const_get(module_name)
        required_method = required_module.method(method_name)
        arity = required_method.arity() # this is how many arguments the method requires, it is negative if a 'catch all' is supplied.
        arity = ((arity * -1) - 1) if arity < 0
        if cells[5..-1].length != arity then
            raise 'Number of parameters supplied do not match method.'
        end
        actual_outcome, actual_output = required_method.call(*parameters)
        # determine the result.
        if (expected_outcome = 'Success') and actual_outcome then
            result = "PASS"
        elsif (expected_outcome = 'Error') and (not actual_outcome) and (expected_error = actual_output) then
            result = "PASS"
        else
            result = "FAIL"
        end
        puts "\nRunning Test: #{method_name} for #{module_name}."
        puts "Expected Outcome: #{expected_outcome}."
        puts "Expected Error: #{expected_error}."
        puts "Actual Outcome: #{actual_outcome}."
        puts "Actual Output: #{actual_output}."
        puts "RESULT: #{result}"
        rescue
            puts "An error occurred: #{$!}"
        end
    end
end

Note that I have dynamically determined the module and method name from the wiki and I have then dynamically called it with the appropriate number of arguments using arity.

When I run it the ruby code the output is:

Running Test: empty_cart for Customer.
Expected Outcome: Success.
Expected Error: .
Actual Outcome: true.
Actual Output: .
RESULT: PASS

Running Test: add_book for Customer.
Expected Outcome: Success.
Expected Error: .
Actual Outcome: true.
Actual Output: .
RESULT: PASS

Running Test: check_out for Customer.
Expected Outcome: Success.
Expected Error: .
Actual Outcome: true.
Actual Output: .
RESULT: PASS

This could be substantially improved but it’s a start. For example, we could easily add timings for each test case.

Next Steps

The next step is to dynamically create a child results page on the Confluence wiki for each time you run a test. That way there is a historical record so you can then schedule your tests to run automatically and check the results later on using the wiki.

I’ll be posting some more information and code in the coming weeks on how to do this.

Click below to see the Watir code I wrote and used.

Continue reading