Introducing the Shoulda Testing Plugin

So we’ve been hinting for some time now that we were going to tidy up the testing helpers we use here, and that’s just what we’ve done.

Update: Added the Why? section below to address rSpec & Test::Spec

Introducing Shoulda!

We had a very hard time coming up with a name for this plugin, mostly because of its somewhat eclectic nature. It does three main things:


Shoulda defines context and should blocks:

class UserTest < Test::Unit::TestCase
  def setup
    # Normal setup code

  def testcanhavenormaltests
    # Normal test here

  context "a User instance" do
    setup do
      @user = User.find(:first)

    should "return its full name"
      assertequal 'John Doe', @user.fullname

This is very much like the rSpec way of doing things, but they can be used along-side normal test method definitions. Also, these context blocks can be nested.


Shoulda also attempts to collect common test patterns into test macros:

class UserTest < Test::Unit::TestCase
  shouldrequireattributes :name, :phonenumber
  shouldnotallowvaluesfor :phonenumber, "abcd", "1234"
  shouldallowvaluesfor :phonenumber, "(123) 456-7890"
  shouldprotectattributes :password
  shouldhaveone :profile
  shouldhavemany :dogs
  shouldhavemany :messes, :through => :dogs
  shouldbelongto :lover


Finally, Shoulda adds a few basic-but-useful utility methods and assertions:

assertdifference(User, :count, 1) { User.create }

assertdifference(User.packages, :size, 3, true) do 

assertcontains(['a', '1'], /\d/)

assertsameelements([:a, :b, :c], [:c, :a, :b])

Why not rSpec or Test::Unit

A lot of people are going to be wondering why we didn’t just go with one of the many new BDD style testing frameworks that are out there, like <a href=“”>Simply BDD, Test::Spec, or the wildly popular rSpec. I don’t want to minimize the work that’s been done on these very cool pieces of software – in fact, Shoulda would never have been written without their example to lead us. But there were some parts of the rest of the plugins that we just didn’t feel right about.

I wrote another post, specifically about rSpec, but here are the major points (most of which apply to all of the plugins):

  • context defined on Kernel, and should defined on Object – This can make it very hard to extend the framework, and honestly just feels wrong. I can imagine that there would be method definition conflicts between the testing framework and the code being tested. I could be paranoid here, but I didn’t want to find out for sure months down the line.
  • Extendibility – I think the real value of this testing plugin is in the focused testing macros, which can test large chunks of common code in a single line. The issue above made these kinds of macros hard to write in the other testing frameworks.
  • Mocking framework built-insoon rSpec won’t suffer from this as much as it does now, but I still don’t like the idea of the testing framework and mocking framework being so interlocked.
  • lambda {}.should.differ(Blog, :count, 1) – This is purely a matter of taste, but we really didn’t see value in the ‘x.should y’ syntax over the ‘assert’ syntax.
  • Compatibility – This one is rSpec specific. As much as I like the format of the rSpec output, it can cause problems with automated programs that are expecting Test::Unit output. Also, having to run both ‘rake spec; rake test’ to see all of your tests pass seems like an unnecessary annoyance.

Docs & Installation

Full RDocs are available here, and the official Shoulda page is here.

We’re having some troubles with our plugin repository working with script/plugin at the moment, so svn access will have to suffice:

svn ls
svn export vendor/plugins/shoulda


Sharpen your programming skills by completing coding exercises that are reviewed by other developers at Upcase today.