In Rob Sanheim’s blog comparing test/spec w/ rspec, Rob pointed out that he had “been following RSpec, the better known Ruby BDD library for awhile, but decided against it since it just doesn’t look practical for use in an established project with around ~400 test cases.”

As it turns out, rspec-0.8 has done a much better job of isolating components. It’s not quite ideal yet, but it is sufficient to support using RSpec’s expectations right in your Test::Unit::TestCases.

To make this happen, you need to require a few things:

require 'test/unit'
require 'rubygems'
gem 'rspec'
require 'spec/expectations'
require 'spec/matchers'

‘spec/expectations’ adds #should and #should_not to your objects. ‘spec/matchers’ provides RSpec’s Expression Matchers, which you then need to explicitly include in the TestCase:

class ThingTest < Test::Unit::TestCase
  include Spec::Matchers

Here’s an example with one passing and one failing test.

require 'test/unit'
require 'rubygems'
gem 'rspec'
require 'spec/expectations'
require 'spec/matchers'

class ThingTest < Test::Unit::TestCase include Spec::Matchers

def setup @thing = Thing.new end

def test_should_have_4_subthings #should fail @thing.should have(4).sub_things end

def test_should_have_3_subthings #should pass @thing.should have(3).sub_things end end

class Thing def sub_things [1,2,3] end end

Assuming that you have rspec-0.8.0 or better, this should produce the following output:

$ ruby thing_test.rb
Loaded suite thing_test
Started
.E
Finished in 0.000642 seconds.

1) Error: test_should_have_4_subthings(ThingTest): Spec::Expectations::ExpectationNotMetError: expected 4 sub_things, got 3 /usr/local/lib/ruby/gems/1.8/gems/rspec-0.8.1/lib/spec/expectations.rb:55:in fail_with' /usr/local/lib/ruby/gems/1.8/gems/rspec-0.8.1/lib/spec/expectations/handler.rb:17:inhandle_matcher' /usr/local/lib/ruby/gems/1.8/gems/rspec-0.8.1/lib/spec/expectations/extensions/object.rb:28:in should' thing_test.rb:15:intest_should_have_4_subthings'

2 tests, 0 assertions, 0 failures, 1 errors

So now, although we’d like to see people who want to use RSpec using RSpec, this should lower the barrier to those who wish to migrate existing systems gradually.

2 Responses to “Spec::Expectations and Test::Unit::TestCase, together again at last”

  1. Rob Sanheim Says:

    Thanks for writing about this, David. Its nice to see that rspec is becoming friendlier for “legacy” rails projects. We have enough code using test/spec now that I’m definitely not going to rewrite existing projects using it, but I’ll certainly consider rspec for new projects. Now, if only mocha would place nice with rspec… =)

  2. David Chelimsky Says:

    FYI – I’ve added an easier way to do this to the soon-to-be-released rspec-0.9

    require 'test/unit'
    require 'spec/test_case_adapter'

    class MyTest < Test::Unit::TestCase #... end