Leaving the beaten track with RSpec

Posted by Craig Ambrose on December 05, 2007 at 07:16 AM

I’ve spent today learning RSpec. To get my head around it, I decided to spec a controller action which I’d already written and tested with Test::Unit. It’s a pretty basic CRUD action, requiring login and ownership of the record.

Here’s the spec and test code side by side:

http://pastie.caboo.se/124898

I’m not sure which one was easier. The RSpec version is certainly a lot longer. Having said that, the Test::Unit one uses fixtures, which aren’t included in the dump.

In RSpec’s favour, is that the specifications run much faster (as they don’t use the database), and they also better decouple the controller from the model, as it’s a more true “unit” test. Having said that, I believe that the RSpec version might actually be a little bit more fragile, as it would fail if the code under test changed to perform the same operation using different methods (such as calling ActiveRecord create, instead of new and save).

Also, some of the things I specified in terms of expectations are actually order dependent, which is not captured in my specs, so if I deliberately messed up the order of some of the code, I might get false positives with my specifications.

For the record, here’s the code under test.


before_filter :login_required, :only => [:new, :create, :edit, :update]
before_filter :load_user
before_filter :current_user_can_edit_user, :only => [:new, :create, :edit, :update]
before_filter :load_user_base_tabs
  def create
@photo_set = PhotoSet.new(params[:photo_set])
@photo_set.profile = @profile
success = @photo_set.save respond_to do |format|
format.html do
if success
redirect_to user_photo_set_path(@user, @photo_set)
else
render :action => 'new'
end
end
end
end
Hierarchy: previous, next

Comments

There are 8 comments on this post. Post yours →

Slightly off topic, but I must say I love the way you use:

success = @photo_set.save

and then “if success” instead of just “if @photo_set.save”

very readable and english like :-)

Thanks David,

Doing that has become a bit of a habit of mine (and many others) since the introduction on respond_to blocks. Obviously I can’t really call @photo_set.save inside respond_to.html, as that section is only supposed to contain formatting login, and although this slightly contrived example only has one block, most of my actions respond to more than one format.

So, will you use RSpec or Test::Unit going forward?

Lots of people at the Sydney Rails meetups swear by RSpec, but Test::Unit has always done the job for me (my impressions seem to mirror yours mostly).

I’m not done with RSpec yet. When I started rails development I had been using TDD for years in a number of languages, and I naturally tried to mock everything out and “unit test properly”. I had great difficulty doing that, and eventually found that doing things the “rails way” was much easier.

However, with RSpec, I’m pleased to see the re-emergence of interest in “real” unit testing (or speccing). Certainly RSpec could be use with heavy use of fixtures, instead of mocking, which would be something of a middle ground. I haven’t had as much trouble with fixtures as some people have, but also there are some things that just seem too painful to test and I just don’t bother, and I’d like to change that.

I did greatly enjoy the workflow of writing specs without any body and then slowly filling them in.

So, I think I need to do some more work with RSpec before I can really form an opinion, but certainly the next time I sit down on that project I’ll be writing more specs, rather than tests, to see how I go.

Craig

I really like Rspec and I love seeing how other people are using it. Thanx for sharing.

In the article you said you have some expectations that are order specific. There is a method in Rspec that you use on expectations to ensure that they occur in the correct order.

my_mock.should_receive(:flip).once.ordered
my_mock.should_receive(:flop).once.ordered

That should make sure that flip is received before flop.

You can find out more at http://rspec.rubyforge.org/documentation/mocks/mocks.html

Thanx again for sharing

Other late-comers to this page (like me :) could benefit of looking up Brynary and some newer posts on unit vs. story or behaviour driven development.

Slightly off topic, but I must say I love the way you use: success = @photo_set.save and then “if success” instead of just “if @photo_set.save”

Well…Lots of people at the Sydney Rails meetups swear by RSpec, but Test::Unit has always done the job for me my impressions seem to mirror yours mostly.

Post a comment

Required fields in bold.