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:
- All your TestCase class files should be in one folder
- Your TestCase class file names should follow a strict and scalable naming convention
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 calledsuite_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 wordaccount
in it, you can get ruby to do the work for you. Replace the contents ofsuite_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!