RSpec: Shoulda Looked At It Sooner

Tháng Hai 26, 2009

Source: http://railstips.org/2009/2/21/shoulda-looked-at-it-sooner

Just a little bit ago I twittered:

I’ve been using shoulda with rspec for past week. Now trying it on fresh rails project and liking it ok thus far.

To which Brandon Keepers replied with:

@jnunemaker what do you like about it?

I started to send a tweet back and realized it would make an ok post here.

History

I remember asking Brandon at RailsConf last year why he liked RSpec so much (I was using test/spec at the time) and his answer was, “I don’t know, just because.”

Of course after that response, he laughed and tried to explain. One thing I’ve noticed is that it is sometimes hard to explain why you prefer a certain tool over another. That said, I am going to give it a shot.

Shoulda with RSpec

When Joe Ferris announced that shoulda macros could now be used with RSpec, I switched away from rspec-on-rails-matchers pretty quickly. I’ve been using shoulda’s macros with RSpec for about a little while and today when I started a new side project, because of my little bit of familiarity and interest due to using it the past while, I thought what the heck, and went all or nothing with shoulda.

Toe Dipping

What is funny, is that I was completely anti-shoulda until they announced RSpec compatibility. I remember thinking, oh great, here comes another stupid testing framework. I looked it over several times and couldn’t find enough coolness to interest me in switching. When they announced that I could dip my toe in while still using RSpec, I gave it a shot. Honestly, without the toe dipping, it would have been a long time, if ever, before I even gave shoulda a fair shot.

The dipping of the toe method reminds me of git-svn. My first git experience was working with an svn repository. The same thing happened. I figured I had nothing to lose by dipping my toe in and a few hours later, I was hooked.

At first, as usual with new things, I was frustrated, followed by excited, followed by frustrated. After an hour or two of adding tests to the project, with the shoulda source code right by my side, things started to kind of click.

My Two Favorite Shoulda Things

1. As I look at my tests from various projects using test/unit, test/spec, rspec and this new project with shoulda, the shoulda tests just seem more readable. I don’t know if it is the context/should verbiage that I like better than describe/it or what, but my test files seem easier to scan and aesthetically more pretty (if that makes sense).

2. I love the shoulda controller macros. They put the few matchers that I created and used with RSpec to shame. That is not RSpec’s fault, I just love shoulda’s. I’m usually most interested in code and syntax, so here is a sample from the project I’m playing with that tests a basic sessions controller.

class SessionsControllerTest < ActionController::TestCase
  context "on GET to :new" do
    setup { get :new }

    should_render_a_form
    should_respond_with :success
    should_render_template :new
  end

  context "on POST to :create with valid credentials" do
    setup do
      User.stub!(:authenticate, :return => users(:jnunemaker))
      post :create, :username => 'jnunemaker', :password => 'secret'
    end

    should_return_from_session :user_id, "users(:jnunemaker).id" 
    should_redirect_to 'root_url'
    should_filter_params :username, :password
  end

  context "on POST to :create with invalid credentials" do
    setup do
      User.stub!(:authenticate, :return => nil)
      post :create, :username => 'jnunemaker', :password => 'fake'
    end

    should_respond_with :success
    should_render_template :new
    should_set_the_flash_to /Could not authenticate/
  end

  logged_in_as :jnunemaker do
    context "on DELETE to :destroy" do
      setup { delete :destroy }

      should 'log user out' do
        session[:user_id].should be(nil)
      end

      should_redirect_to 'login_url'
    end
  end
end

Note: I’m also using Jeremy McAnally’s stump for stubbing the User#authenticate method which makes an external web service call, his matchy library for the fancy session[:user_id].should assertion, and a macro I stole (logged_in_as) to easily setup authentication for controller tests. Nothing fancy, but I just like the way it flows.

Simple Model Test

If you are in the mood for more code, here are some of the tests from my user model. Yes, I’m making a twitter client. I’m dissatisfied with pretty much all the twitter clients out there (and I’ve used them all) so I decided to whip one together. I’ll probably open source it at some point.

class UserTest < ActiveSupport::TestCase
  should_have_many :user_statuses
  should_have_many :statuses, :through => :user_statuses

  context "#sync_with_twitter" do    
    should "not assign ignored attributes" do
      tweeter = new_tweeter(:id => '1234', :name => 'Shaq', :screen_name => 'THE_REAL_SHAQ', :created_at => '2006-08-13 22:56:06')
      User.sync_with_twitter(tweeter, 'secret')

      user = User.find_by_twitter_id('1234')
      user.created_at.should_not == user.twitter_created_at
    end

    should "create non-existant user" do
      assert_difference 'User.count' do
        tweeter = new_tweeter(:id => '1234', :name => 'Shaq', :screen_name => 'THE_REAL_SHAQ')
        User.sync_with_twitter(tweeter, 'secret')
      end
    end

    should "update existing user" do
      user = users(:jnunemaker)
      tweeter = new_tweeter(:id => user.twitter_id, :name => 'New Name')

      assert_no_difference 'User.count' do
        User.sync_with_twitter(tweeter, 'secret')
      end

      user.reload
      user.name.should == 'New Name'
    end
  end

  def new_tweeter(attrs)
    tweeter = Twitter::User.new
    attrs.each { |k,v| tweeter.send("#{k}=", v) }
    tweeter
  end
end

Again, I’m using Jeremy’s matchy (mentioned above) to get the .should == syntax. I still enjoy RSpec, but I’m pretty impressed with Shoulda. It feels very scannable/readable and the macros are really handy, both for testing models and controllers.

Oh, and for those who are wondering, all I did to set things up is install the gems and add the following to my config/environments/test.rb file.

config.gem 'thoughtbot-shoulda', :lib => 'shoulda', :source => 'http://gems.github.com'
config.gem 'jeremymcanally-stump', :lib => 'stump', :source => 'http://gems.github.com'
config.gem 'jeremymcanally-matchy', :lib => 'matchy', :source => 'http://gems.github.com'

Shoulda thoughts and reactions? Maybe the shoulda users out there could chime in with what they like best. I am also curious what is holding back others who haven’t tried shoulda out yet.

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s

%d bloggers like this: