I spent some time last week making the Koala test suite compatible with Rails 1.9/Minitest/RSpec 2/Rails 3. Along the way I encountered a few issues and learned a few lessons that may be useful to those making the same transition.

Undefined method ‘it’, ‘before’ or ‘after’ for MyTests:Class (NoMethodError)

These errors baffled me at first — I couldn’t figure out why my test classes, which worked fine with RSpec 1.3, threw errors on the most basic RSpec commands. Fortunately, these errors only happened for some of my test classes, and after some trial, error, and comparison I figured out out the cause. In RSpec 2, all tests and before/after blocks must be nested inside a describe block. RSpec 1.x was more forgiving, letting you write tests that lived directly inside the class.

    class MyTests < Test::Unit::TestCase
      it "should do stuff" do
        @stuff.should be_a(Thing)
      end
    end

XXX
    class MyTests < Test::Unit::TestCase
      describe "basic stuff" do
        it "should be do stuff" do
          @stuff.should be_a(Thing)
        end
      end
    end

Shared example groups are isolated

In the course of researching the previous issue, I stumbled across the following text tucked away at the bottom of the rspec-core upgrade guide:

NOTICE: The including example groups no longer have access to any of the methods, hooks, or state defined inside a shared group. This will break specs that were using shared example groups to extend the behavior of including groups in any way besides their intended purpose: to add examples to a group.

As it didn't help with my immediate problem I filed it away and moved on, but I was lucky I saw that. It turns out our test suite was doing exactly that what this change is meant to prevent: using shared example groups to set up context. In our case, we used a group to manage OAuth tokens and cleanup for live (or simulated live) testing. Moving the code from a shared example group into a module solved the problem. (See below.)

    shared_examples_for "my tests" do
      before :each do
        @foo = Thing.new
      end
    end

    class MyTests < Test::Unit::TestCase
      it_should_behave_like "my tests"

      describe "basic stuff" do
        it "should do stuff" do
          @foo.should be_a(Thing)
        end
      end
    end

XXX
    module MyTestHelper
      def self.included(base)
        base.class_eval do
          before :each do
            @foo = Thing.new
          end
        end
      end
    end

    class MyTests < Test::Unit::TestCase
      include MyTestHelper

      describe "basic stuff" do
        it "should do stuff" do
          @foo.should be_a(Thing)
        end
      end
    end

spec_helper and test classes

With Ruby 1.9.2, Minitest provides a backward compatible syntax that works with RSpec. Some of this is covered in the upgrade guide (link); I also found the BLOG POST (link) useful.

Conclusion

Overall, migrating Koala was quite painless; the gem itself required no changes and all the test suite changes were to form rather than substance. Upgrading Koala has made me very excited to get started with Ruby 1.9.2 and Rails 3, and I'm sure this won't be the last blog post on the subject.

Cheers,

Alex

Links