An interesting read:
http://37signals.com/svn/posts/2742-the-road-to-faster-tests
An interesting read:
http://37signals.com/svn/posts/2742-the-road-to-faster-tests
TURN (“Test::Unit Reporter (New)”) aims to fix test::unit‘s default output. Instead of waiting until the end of a test run for failure details, Turn displays failures immediately. It looks promising…
—UPDATE—
Since I wrote this post, I have put together a ruby gem designed for testing WPF UIs called ‘bewildr’. I wrote up an introductory post about bewildr here. Bewildr removes the need for using White – it’s written in ruby, for ruby! You’ll find its API clean and idiomatic. Anyway, back to the original post…
—————–
…and you thought ruby was only good for web testing…
So… having previously failed at getting ruby-based automated testing of WPF working, I attacked it from a different angle and succeeded! The difference is that this time I used IronRuby instead of ruby. In doing so, the White Automation library could be used out-of-the-box! It’s time to throw away your expensive, proprietary test tools and replace them with open source tools instead! Here’s how it’s done:
I’m presuming that you know to run ruby files in IronRuby using the ir command, not the standard ruby command, iirb instead of irb and irake instead of rake.
First thing, you need to gain access to White in your project. To do that, put the following at the top of your app (eg: your env.rb file in cucumber):
$LOAD_PATH << File.expand_path("lib/White_Bin_0.19")
require "White.Core.dll"
require 'UIAutomationTypes, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
module IronRubyHelpers
def r_array_to_cs_array(args)
System::Array[System::String].new(args.map {|arg| arg.to_s.to_clr_string})
end
def r_string_to_c_string(r_string)
System::String.new(r_string)
end
end
This requires some explanation… The first line puts the directory containing the White.Core.dll file on the load path. In this case, I’ve taken the White_Bin_0.19 directory that was created when I expanded the zip I downloaded from the White site, and put it inside the lib directory in my NetBeans project. The next line requires the White library. The line after that loads the UIAutomationTypes.dll – you’ll need this if you want to find WPF objects by their type.
Next, the IronRubyHelpers module… it contains 2 methods: one converts a ruby array to a dot net array (required whenever a White object method takes an array as an argument, eg: menu interaction), and the other converts a ruby string to a dot net string (sometimes required when a White object arg takes a string).
That’s all the setup you need.
Now we start dealing with White… Here’s how to start a WPF app :
@app = White::Core::Application.Launch("c:\my_app\example.exe")
And here’s how to kill it:
@app.kill
The Launch(string) method is one of many ways to start an app. Check out the Application.cs documentation to see how else it can be done (I can’t get AttachOrLaunch to work – ymmv).
You get access to objects by using the window that they’re in. That means you need to get the window first. Here’s how it’s done:
@main_window = @app.get_windows.select{|window| window.title == "My Window Title"}.first
That will get you a window whose title matches “My Window Title” exactly. If you want a bit more flexibility (eg: if your app displays its version number in the title and you don’t want to have to change your recognition string everytime you get a new build), you can use the following regex-powered window finder:
@main_window = @app.get_windows.select{|window| window.title =~ /My App, version (.*)/}.first
Your window takes a while to appear? Here’s how to wait for it:
Timeout.timeout(10) do
sleep 0.2 until @app.get_windows.select{|window| window.title == "My App"}.size > 0
end
Now you’ll wait for up to 10 seconds checking ~5 times a second to see if a window entitled “My App” appears (it only takes a tiny tweak to make it use regex). If it takes longer than 10 seconds you’ll get a Timeout exception.
Now that we can get hold of windows, we can look inside them and get access to the object that they contain. White uses static methods on SearchCriteria to access object. Generally, you’ll need 2 bits of info:
Here are some examples:
@chk_visibility = @main_window.get(White::Core::UIItems::Finders::SearchCriteria.ByAutomationId(r_string_to_c_string("visibleCheckBox")))
Hey, no one said it was pretty. Here we’re getting a checkbox that lives in the main window. We’re identifying it by its automation id, which happens to be “visibleCheckBox”. Another example:
@cmb_zoom = @main_window.get(White::Core::UIItems::Finders::SearchCriteria.ByControlType(System::Windows::Automation::ControlType.ComboBox))
Here we’re getting the only combo box in the main window. This time we’re searching by ControlType. You can find a full list of the available control types here under the “Fields” section.
There are a few more ways to use SearchCriteria, you can read about them in the SearchCriteria.cs documentation.
And now to object interaction… Once you’ve got your object reference, you can call methods on it and hope it responds. Here are some examples:
@chk_visibility.checked
…will return true or false based on whether the checkbox is checked – read about the available methods on checkbox here. Another example:
@cmb_zoom.select(r_string_to_c_string("200%"))
This will select the “200%” option from the combo box.
Depending on the object type you could call .click, .value = "hello", .double_click, etc.
Since using the window menu doesn’t fit the standard object-locator pattern, we’ll cover that here.
def select_menu_item(*args)
my_menu_bar = @main_window.menu_bar
my_menu_item = my_menu_bar.menu_item(r_array_to_cs_array(args))
my_menu_item.click
end
select_menu_item("File", "Open...")
Using window menus is a bit weird in White. The easiest way to go about it is to use the select_menu_item above. It gets the menu bar out of the window, does some ruby-to-dot-net magic with the arguments and then clicks the menu item. I’ve included an example call to the method that does the standard File->Open action.
Because we’re using IronRuby, there’s a quirk you need to be aware of – you may have spotted it already… IronRuby translates White’s CamelCase methods to the standard ruby_underscore_case. Eg:, if the White documentation says that a particular object supports the “DoubleClick” method, you can call that method in your ruby scripts with “double_click”. You get used to it.
…or lack of same. White is slow. And buggy. IronRuby startup time is slow too. I’ve found loads of places where White claims to do something (eg: table interaction), but what’s there isn’t unusable. Some of the stuff that does work only works often, not all the time. I’ve rewritten some of the buggy functionality using the low level interaction libraries provided by microsoft and the replacement code runs several orders of magnitude faster than white. Please don’e expect fast execution – you just won’t get it. Be prepared for molasses-speed testing.
I’ve put together a badly designed set of tests around Paint.NET (3.5.3 at time of writing) using Test::Unit. It’s a NetBeans project, but even so you’ll need to run the tests off the command line (there’s no IronRuby-NetBeans support that I can find). Make sure to have Paint.NET installed in its default location and then try running “irake test” in the project directory… and have patience – it crawls. It takes around 2 minutes to run 4 tests.
>>> Download my example project here <<<
Enjoy!
There aren’t enough UI test automation success stories documented on the net, so here’s my contribution.
This post is about how we started with zero automated UI testing capability, and how a couple of months later we had the capability to run 1,000 tests in 20 minutes (you may also notice some gorilla-style chest-beating). Not only that, our test execution results were always spot on (no false passes, no false fails), and our framework was easy to maintain and extend. Here’s how we did it and the lessons we learned along the way.
After several false starts with UI testing (involving QTP and watin and fitnesse and and and…), it finally got off the ground after I demonstrated what could be achieved with watir. This was the first lesson for me: demonstrating working code makes for a far better case than “just believe me, I’ve done it before, it’ll work fine”. Realizing this, I spent a weekend putting together a simple ruby/test::unit/watir testing framework.
When, on monday morning, I demoed a bunch of working tests that could run over and over and over and each time give the correct results to a room full of doubters, it was decided that we’d give ruby/test::unit/watir a go.
In order to avoid the biggest mistake made in previous attempts at UI automation, I insisted on agreement to a very important constraint: the ruby/test::unit/watir framework would only test the web app part of the system. One of my philosophies when it comes to UI automation is: “use the right tool for the right job”. There would be no scope creep. The framework would be used for the web app only. The WPF fat client could be tested with something else – anything else, just please don’t subvert ruby/test::unit/watir for testing anything else but the web app.
This was all part of expectations management; over the years I’ve learned that this is one of the most important things when doing automated UI testing. It’s worth a separate post – I’ll get around to it.
The framework I came up with that weekend was very simple (and very unoriginal – I’ve done similar stuff before): each page in the app would be represented by a ruby module. Each “page module” would contain one method per control on the web page; the method when called would return the required object. Eg:
module HomePage
def home_page_sign_in_link
@browser.link(:xpath, "//a[contains(@href,'signin')]")
end
def home_join_button
@browser.button(:id, "join")
end
end
My experience is that IDs on objects often can’t be trusted. What I’ve found is that they usually get put in during development and that they are removed when they’re not required. If I write my object recognition code to depend on an ID I usually regret it. I’ve learned that xpath is often more reliable – IDs tend to disappear. Where I have reliable IDs, I’ll use them. But for anything else, I use xpath. I find myself maintaining ID-based object recognition a lot more than xpath-based object recognition. Your mileage may vary.
Each of these page modules was “mixed in” to a common module which was then mixed into the test, making each object in the system available to the test without having to deal with namespacing. Not the prettiest solution, but it got us working very quickly. We surprised ourselves by having no method name clashes – mainly due to the object naming convention we used.
Our app uses restful services so the net::http libraries were great. The calls were wrapped up in classes and placed alongside our test-data-generation code (random strings, valid usernames, etc). We wrote them to be independent of the rest of the framework (apart from the central config file that pointed them at the right environment) so that we could use them whenever and however we liked. This philosophy was applied to as much of the framework as possible – to the greatest extent possible we kept everything independent and modular. This allowed us to keep up with sweeping changes in the app we were testing. We had a lot of sweeping changes; to many people’s amazement (not least our own!) we were able to keep up with everything thrown at us.
One of watir’s greatest features which doesn’t get nearly enough air time is the “checkers” functionality. Every time a page is visited you can run custom code you’ve wrapped up in a ruby proc. Environment instability usually manifests itself in obvious ways. Watir checkers allow you to recognize these as soon as they appear. If, in your checker code, you raise an exception with a fixed message, you can find these when the test is done and mark the tests as “failed due to environment instability”; or you can be more specific, e.g: “failed due to database connection going down, again”. This saves us hours of work every day. Literally, hours.
Our test execution script keeps note of tests that failed. When all the tests have been run, the tests that failed get run again in the hope that environment instability “got better”. We’d have to rerun those tests manually at the end of a run anyway, so why not automate it? A big time saver.
We used test::unit for executing the tests. It’s simplicity and rock-solid nature made it a good choice to start the framework with. It is also easily expanded/monkey-patched – we added a few things to it.
Though I have ruby experience, everyone else on the team had a C#/NUnit background; test::unit helped bridge their knowledge gap. Conceptually, test::unit and NUnit are identical (both are xunit tools) – the similarity meant one less thing for the others to learn. When under pressure, that was a good thing.
Netbeans‘ integration with test::unit is great, so we decided on using it for our IDE. It turns out that NetBeans is a great IDE for watir testing; I heartily recommend it. The green ticks and red crosses were comforting to all the right people, the ease of viewing the source code of the watir/firewatir libraries was great, its intellisense wasn’t as bad as I was expecting it to be and its svn integration is better than anything else I’ve used so far. It’s also free so I didn’t have to get approval to buy it! It has loads of useful plugins too.
We used firefox (and therefore firewatir) because we needed to spoof useragents and headers – using firefox profiles meant we could test the mobile, browser and fat client webstores. Using firefox meant we could use plugins; here are the ones we found most useful:
One area where testing is usually decades behind development is in the use of version control. This is probably due to the fact that most commercial tools make it less than trivial to do (the QTP and RFT test file formats are hardly version-control-friendly).
One of the many joys of using watir for UI testing is that using version control is simple – there are no ‘project files’ to worry about, no accompanying files that you need to check in when you change a test file, no bizarre links across directories, no weird inter-file dependancies.
Using version control for our tests and framework meant that we were free to change stuff as we saw fit – if something didn’t work we could just revert. I can’t recommend using version control enough. The “blame” feature in svn was particularly useful
We got our super-fast execution time by cheating: we parallelized the execution of the tests. We used a Mac Pro (16GB RAM, 8 core, 4xHDD), the Parallels virtualization software to run 12 VMs, and a shonky “n mod 12″ function to decide what tests to run on each VM (we tried to get testjour working but it needs a fair bit more dev and documentation before it works as advertised and becomes usable).
One advantage of using a Mac (apart from its rock-solid stability) was “Exposé” – we could see all 12 VMs running at once. The amount of people who walked past our desk and got hypnotized by seeing 12 tiny PCs each executing as if they were self aware… – good PR for our team!
It doesn’t matter if you can run a million tests in 5 minutes, if the results aren’t accurate and sanitized quickly. We’re quite proud of the fact that we provide our results within 5 minutes of finishing the last test (usually straight away). We’ve put a lot of effort into being able to do this and it’s one of the biggest selling points of the framework we’ve written. Here’s what we’ve done to get to this stage:
Initially, there was a lot of hostility toward the project – understandably! UI testing doesn’t have a good history where I work at the moment. One of the scrum masters pointed out that the best PR was fast, consistent and accurate test results and he was right. But there are a few more things that gave people reason to change their opinion.
That’s all for now!
We have close to 1,000 watir tests that we’re beginning to migrate from test/unit to cucumber. The “Beginning with Cucumber” Railscast is a great introduction to how cucumber works – it’s quite rails-centric, but you’ll get the idea.
I’ve recently found a couple of instances of tests with the same test name in the same test::unit TestCase class. This is a bad thing, because the when the ruby interpreter reads the file in, it will ignore all methods by the same name apart from the last one, which is the one it will use. Some code to explain:
require 'test/unit'
class MyTest < Test::Unit::TestCase
def test_me
puts "aardvark"
end
def test_me
puts "zebra"
end
end
If you run this code, you’ll get “zebra” printed to the console, not “aardvark”, because the last method definition for test_me is the one that is used.
You’ve probably worked out how this can be a very bad thing in testing – if in a TestCase class you have several test methods by the same name (copy-and-paste mistakes), you’ve got tests which don’t get executed! Then, as happened to me, you’ll get a dev coming over to you asking why your tests didn’t find a particular bug – the test which would have found the bug was never run, that’s why!
To find all instances of duplicate test names, I wrote the code below. To use it, save it to a file, set the root_test_folder variable to point to your root testing folder, and run it. If it finds duplicate tests, it’ll print out the file containing them, the duplicate test names, and how many times the test name is defined in the offending file.
root_test_folder = "/Users/nat/dev/my_testing_project/test"
unless File.exist?(root_test_folder) && File.directory?(root_test_folder)
abort("You haven't specified a directory in root_test_folder")
end
all_test_files = []
Dir.glob(File.join(root_test_folder,'**/*.rb')).each do |file|
f = File.new(file)
all_test_files << file if f.read =~ /class\s+.*\s+< Test::Unit::TestCase/
end
all_test_files.each do |test_file|
test_names = []
test_file_contents = File.new(test_file).read
test_file_contents.each_line do |line|
test_names << line.strip.gsub(/^(\s)*def\s+/,"") if line =~ /^(\s)*def\s+test_[\d\w]+(\s)*$/
end
has_duplicate_test_name = false
b = test_names.inject(Hash.new(0)) {|h,i| h[i] += 1; h }
b.each {|dupe_test_name,count| has_duplicate_test_name = true if count > 1 }
if has_duplicate_test_name
puts test_file
b.each {|dupe_test_name,count| puts "#{count}x #{dupe_test_name}" if count > 1 }
puts ""
end
end
NB:
- it assumes that each test file only contains one TestCase class
- it has very little error checking and is quite inefficient – but it does the job
- if you have any enhancements, please leave a comment
A test team usually has a need for a few fixed test suites, eg: a sanity suite or a suite which contains all tests for a full run. There’s usually also a need to be able to create suites with arbitrary tests in it, eg: a suite that tests all account management functionality or a suite that runs all tests for a particular platform. There is often the need to quickly throw together a suite which can be used to regression-test a specific area of functionality.
If you’re using a ruby + watir + test::unit framework, there’s a simple way to get all of the above flexible suite buliding functionality. Here’s how…
First of all, a few prerequisites… They are:
For the purposes of this blog post, we’ll use a simple naming convention: all test files in our imaginary project begin with test_ , all suite files begin with suite_ and all test files that test account functionality contain the word account in their file name.
Test::Unit has the concept of ‘require files’… any file that requires a TestCase file will cause the test to be executed (unless something has been done to prevent tests from being run). These require files can be used as test suites – any tests that are ‘required’ in the test suite will get executed! So, the first way you could use these require files is to individually require each TestCase file. Here’s an example… a file called suite_account_tests.rb containing the following lines; each one will load a file containing a TestCase file:
require "test_account_join"
require "test_account_close"
require "test_account_upgrade"
require "test_account_change_details"
This works, but it is laborious to build, and even more of a pain to maintain. There has to be a better way… and here it is: instead of requiring each individual file that has the word account in it, you can get ruby to do the work for you. Replace the contents of suite_account_tests.rb with the following line:
Dir.glob(File.join(File.dirname(__FILE__), '*account*.rb')).each {|f| require f }
That one line will read in all ruby files that contain the word ‘account’ in the file name, and that live in the same directory as the suite_account_tests.rb file. Then, because this is just a test::unit require file, all the TestCase classes that got required will get executed. Awesome. No need to update the suite file if an account-related TestCase file is added or deleted; it will pick up any changes automatically. All that’s required is a good naming convention…
The power of that one-liner lies in the Dir.glob function. It takes filename ‘patterns’ (shame it doesn’t take a regex) documented in the Dir.glob rdoc to decide which files to run. If you’ve got a strict naming convention, you’ll find that the Dir.glob functionality lets you create suites very quickly. If you can’t create suites quickly now, you’ll find that it’s great PR for the test team when you can!
Using these patterns, with the following one-liner we can build a suite that will run all tests:
Dir.glob(File.join(File.dirname(__FILE__), 'test_*.rb')).each {|f| require f }
All files that begin with test_ will get required and executed. This works because of the file naming convention we’re using. Only TestCase files begin with test_, so we can be sure that only tests are getting loaded. Specifically, suite files won’t be loaded as their file names begin with suite_, not test_. Anyway, you get the idea.
There’s nothing stopping you from combining the two approaches. You can have a require file that uses both the Dir.glob approach that also has individual requires if the suite needs to include specific TestCases classes.
One non-obvious advantage that this Dir.glob approach to suite files gives you is that you won’t ‘lose’ tests any more. I’ve found that when I’ve used the individual-require approach, on occasion I forget to add a require to the suite when I create a new TestClass file. I end up with tests that gather dust – they never get run. They are forgotten and left to rot. By the time I find them again, the tests are so out of date that they often need rewriting, never mind editing!
Ruby gives you a whole load of power for free; you may as well use it!
Test::Unit‘s lack of pretty xml/html output led me to look around to see what was available. Turns out that there’s a very simple way to get html output… run your Test::Unit tests with rspec! Here’s a contrived and simple example of how it’s done.
We’ll start with a file called test_unit_to_rspec.rb containing only two tests; one that passes and one that fails. Here’s the code:
require "rubygems"
require "test/unit"
class SomeTests < Test::Unit::TestCase
def test_that_passes
assert(true)
end
def test_that_fails
assert(false)
end
end
To run this, we call ruby test_unit_to_rspec.rb and we get the following output:
Loaded suite /Users/nat/dev/test_unit_to_rspec
Started
F.
Finished in 0.011906 seconds.
1) Failure:
test_that_fails:8
is not true.
2 tests, 2 assertions, 1 failures, 0 errors
A ‘.’ and an ‘F’ in the result tells us that one test passed and one failed. Notice, no pretty html. No xml. This is a sad state of affairs and needs to be fixed. We want pretty. We want red. We want green. We want output that will be useful to people other than the test team. So… to fix this…
First, you’ll need to install the syntax gem (gem install syntax). This adds extra prettiness to the output – and that’s what we’re about at the moment! Then, in our test_unit_to_rspec.rb file…
…replace :
require "test/unit"
…with:
require "spec/test/unit"
The new code will look like this:
require "rubygems"
require "spec/test/unit"
class SomeTests < Test::Unit::TestCase
def test_that_passes
assert(true)
end
def test_that_fails
assert(false)
end
end
Next, run your tests using the following command (notice, no ruby in the command):
spec test_unit_to_rspec.rb -f h > results.html
When the run is finished, you’ll find pretty html output in the new file named results.html; here’s what it looks like:

Pretty! Red! Green! Summaries! The code that failed! A whole new world of beautiful (and useful)…
Note that this is only the first step in converting to rspec from test::unit. Doing the above will give you none of the power of rspec, only the pretty output. Also, I imagine that as I get around to converting bigger test::unit projects, conversion won’t be this easy…