RSpec 1.0 tutorial - before and after

Posted by Ken Brooks Thu, 24 May 2007 22:49:00 GMT

Tonight we’ll be starting down the road of those refactorings I promised and along the way we’ll introduce before and after.

First lets change that snowball itself to be a little more rubyish. In this case that means we will use symbols for the color.

class Snowball
    def initialize
        @color = :WHITE
    end

    def color?(color)
        @color == color
    end
end

Now we can modify the spec to do the same, passing in symbols for the color param.

require 'snowball'

describe Snowball do

    before(:each) do
        @snowball = Snowball.new
    end

    it 'Should NOT be yellow' do
        @snowball.should_not be_color(:YELLOW)
    end

    it 'Should be white' do
        @snowball.should be_color(:WHITE)
    end

    after(:each) do
        @snowball = nil
    end
end

You may have noticed that I did a little more than change the params to use symbols. There are now calls to before and after. If you are from an xUnit background you can think of these as setup and teardown. The before method runs prior to each example. before(:each) is the same as before because :each is the default param. The after method runs post each example. The same default of :each applies to after so after(:each) is identical.

Updated 2007-05-25

Aslak (Core developer of RSpec) was kind enough to point out something that I should have clarified:

Each example (instance) runs in a new instance anyway, and the instance variables are garbage collected. The after(:each) here has no effect, and since it has no effect, doing it is confusing.

So in my example above the after method is not doing anything of value. That @snowball will be garbage collected without having to set it to nil. I just needed something to plop in there to show that I could be doing something.

End Update

There are also before(:all) and after(:all) that can be used. These are mostly discouraged as it may cause side-effects by having dependencies between examples. I came across a scenario at work (in Java-land) where this actually applies. I was using JUnit to write a func test that can be used as a test client of a deployed J2EE service. Before any calls can be made to the service we must initialize (authenticate). Once that initialization is done then we can call our service as many times from anywhere in our code using a static service wrapper. So in my test since there is only one setup method I was forced to write code similar to this:

    private static boolean initialized;

    public void setUp() {

        if(!initialized) {
            SubSystem.init();
            initialized = true;
        }

        doSomeOtherSetupTask();
    }

That saves the overhead of authenticating before each test. Unfortunately its ugly to me.

In rspec (altho I’m not sure I would use it to drive a client test like I did with JUnit) I suppose that code would look like this:

    before(:all) do
        sub_system.init
    end

    before(:each) do
        do_some_other_setup_task
    end

Now that is tasty goodness.

Tags ,  | 2 comments

Comments

  1. Aslak Hellesøy said about 2 hours later:

    Hi, and thanks for writing the intro.

    I realise it was probably just for the sake of the example, but I just want to mention that defining an after(:each) block to reset instance variables is discouraged.

    Each example (instance) runs in a new instance anyway, and the instance variables are garbage collected.

    The after(:each) here has no effect, and since it has no effect, doing it is confusing.

  2. sevensoft said about 2 hours later:

    You are completely correct and I weighed that option before posting it but left it in just for the sake of the example like you said.

    Perhaps I could have noted that in the article. Might go update it just to make sure that is clear..

    btw.. being somewhat newish to the ruby/rails world It took me a minute to realize the benefit of RSpec. I couldn’t grasp why anyone would come up with another xUnit type framework. By the time I read a little further on the RSpec site it was perfectly clear that this (if nothing else) is a phenomenal way to approach testing and get documentation all in one shot. DRY indeed.

    So to you and your developers a hearty ‘Thumbs up’ for turning a good development concept on its side and making it fun and useful.

    Now i’m looking for ways to fit this into my corporate J2EE worklife via JRuby.

    Thanks for the comment btw.

(leave url/email »)

   Comment Markup Help Preview comment