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.

Advertisements

Check out the great book for beginner at: http://book.merbist.com/

Merb, DataMapper and RSpec are all open source projects that are great for building kick-ass web applications. They are all in active development and although it can be hard, we’ll try our best to keep up-to-date.

Merb

Merb is a relatively new web framework with an initial 0.0.1 release in October 2006. Ezra Zygmuntowicz is Merb’s creator, and continues to actively develop Merb along with a dedicated development team at Engine Yard and many other community contributors.

Merb has obvious roots and inspiration in the Ruby on Rails web framework. If you know Ruby and have used Rails you’re likely to get the hang of Merb quite easily.

While there are similarities, Merb is not Ruby on Rails. There are core differences in design and philosophy. In many areas that Rails chooses to be opinionated, Merb is agnostic – with respect to the ORM, the JavaScript library and template language. The Merb philosophy also disbelieves in having a monolithic framework. Instead, it consists of a number of modules distributed as Ruby gems. This means that it is possible to pick and choose the functionality you need, instead of cluttering up the framework with non-essential features.

The merb gem installs merb-core, a series of plugins as well as a default ORM (DataMapper); all you need in order to get started straight away. The benefit of this modularity is that the framework remains simple and focused with additional functionality provided by gems.

Thanks to Merb’s modularity, you are not locked into using any particular libraries. For example, Merb ships with plugins for several popular ORMs and provides support for both Test::Unit and RSpec.

merb-core alone provides a lightweight framework (a la camping) that can be used to create a simple web app such as an upload server or API provider where the functionality of an all-inclusive framework is not necessary.

DataMapper

DataMapper is an Object-Relational Mapper (ORM) written in Ruby by Sam Smoot. We’ll be using DataMapper with Merb. As previously mentioned, Merb does not require the use of DataMapper. You can just as easily use the same ORM as Rails (ActiveRecord) if you prefer.

We have chosen to use DataMapper because of it’s feature set and performance. One of the differences between it and ActiveRecord that I find useful is the way database attributes are handled. The schema, migrations and attributes are all defined in one place: your model. This means you no longer have to look around in your database or other files to see what is defined.

While DataMapper has similarities to ActiveRecord, we will be highlighting the differences as we go along.

RSpec

RSpec is a Behaviour Driven Development framework for Ruby. It consists of two main pieces, a Story framework for integration tests and a Spec framework for object tests. Both these components are implemented as Domain Specific Languages which help to make the stories and specs created more readable.

Merb currently supports the Test::Unit and RSpec testing frameworks. Both Merb and Datamapper use the RSpec testing frameworks and so we will be covering some aspects so that you may use it for your own applications.

What About Ruby On Rails?

[Merb is] Harder, Better, Faster, Stronger, to quote Daft Punk – Max Williams

So what’s the big deal? We have Ruby on Rails and that’s enough, isn’t it? There is little doubt that Ruby on Rails has rocked the web application development world. You have to give credit where credit’s due, and Ruby on Rails is definitely a great web framework. However, there is no such thing as a one-size fits all solution. Ruby on Rails is opinionated software which provides many benefits such as Convention over Configuration. On the other hand, this also means that Ruby on Rails can be unforgiving if you don’t want to do things ‘the Rails way’.

Where Rails is opinionated, Merb is agnostic. For example, you can easily use your favourite ORM (ActiveRecord, DataMapper, Sequel) or none at all.
Similarly, you can choose the Javascript library and template language that you are most comfortable with, or that best meets the requirements of your specific project.

If performant were a word, Merb would be it. One of Merb’s design mantras is “No code is faster than no code”. Merb has super-fast routing and is thread-safe. The core functionality is kept separate from the other plugins and it uses less Ruby ‘magic’, making it easier to understand and hack.

Rails (and consequently Ruby) has received a lot of criticism for not being suitable for large scale web applications, which isn’t necessarily true. Merb has been built from the outset to prove that Ruby is a viable language for building fast and scalable web applications.

At the end of the day it’s about choice. There are many new Ruby frameworks springing up, undoubtedly encouraged by the success of Rails. In our opinion, Merb shows the most promise of these.

If you’d like to take a look at some other frameworks these links should get you started: