RSpec: Fuubar + Breaking Tests into Suites

Back | rspec, art.sy, rake, rails, ruby, testing | 8/16/2011 |

Inspired by this post on RSpec best practices and updated for RSpec2.

We’re rapidly approaching 2000 tests in our main project, adding about 100 tests every week. Everyone got really crafty at figuring out the optimal terminal window width to make the twenty or so rows of green and yellow dots from RSpec progress to align nicely. So we replaced the RSpec formatter with the awesome Fuubar (see introductory post) which now gives us ETA and shows error details as they appear. Nice.

image

The really annoying part of RSpec is that tests can run in any order. This depends on file timestamps as RSpec globs the files. What I’d really want is to run short domain model tests first and long UI Capybara tests last. This way I’ll be catching errors sooner. Lets break the tests up into suites. Add lib/tasks/test_suites.rake. Note that pattern can take an array and that this actually generates Rake tasks.

  1. require 'rspec/core/rake_task'
  2.  
  3. SPEC_SUITES = [
  4.   { :id => :models, :title => 'model tests', :pattern => "spec/models/**/*_spec.rb" },
  5.   { :id => :api, :title => 'api tests', :pattern => "spec/api/**/*_spec.rb" },
  6.   { :id => :controllers, :title => 'controller tests', :pattern => "spec/controllers/**/*_spec.rb" },
  7.   { :id => :views, :title => 'view tests', :pattern => "spec/views/**/*_spec.rb" },
  8.   { :id => :misc, :title => 'misc tests',
  9.       :pattern => [ "spec/lib/**/*_spec.rb", "spec/mailers/**/*_spec.rb" ] },
  10. ]
  11.  
  12. namespace :spec do
  13.   namespace :suite do
  14.     SPEC_SUITES.each do |suite|
  15.       desc "Run all specs in #{suite[:title]} spec suite"
  16.       RSpec::Core::RakeTask.new(suite[:id]) do |t|
  17.         t.pattern = suite[:pattern]
  18.         t.verbose = false
  19.       end
  20.     end
  21.     desc "Run all spec suites"
  22.     task :all => :environment do
  23.       SPEC_SUITES.each do |suite|
  24.         logger.info "Running #{suite[:title]} ..."
  25.         Rake::Task["spec:suite:#{suite[:id]}"].execute
  26.       end
  27.     end
  28.   end
  29. end

Run rake -T for a list of generated tasks. We can now run rake spec:suite:all or individual suites with, for example, rake spec:suite:models.