RSpec vs Test::Unit

by woody2shoes on July 9, 2009

Having used both Test::Unit and RSpec, I have to agree with Jim Weirich: the difference between the two is primarily semantics. It seems to me that functionally, they are both equally capable of verifying and specifying code. However, the way in which you write the tests—the semantics—is the primary difference between the two. That being the case, I prefer the semantics of RSpec.

Jim’s post was written back in 2005. Since then, RSpec has developed it’s own Domain Specific Language (DSL) which is really the thing that draws me to it. It feels more natural to develop a test in RSpec than it does in Test::Unit. Here’s a quick example:

Test::Unit

class UserTest < Test::Unit::TestCase

  def setup
    @user = User.new
  end

  def test_name_setter
     assert_nil @user.name, "User's name did initialized to something other than nil."
    @user.name = "Chuck"
    assert_equal @user.name, "Chuck", "@user did not return 'Chuck' when it was called."
   end

 end

RSpec

define "User" do
  before(:each) do
    @user = User.new
  end

  it "should assign a value to the name when the setter is called and return it when the getter is called" do
    @user.name.should be_nil
    @user.name = "Chuck"
    @user.name.should equal "Chuck"
  end
end

Here are the things I like about RSpec that I don’t get from Test::Unit.

First, I can read aloud to another developer and he understand exactly what I’m testing. In other words, I don’t have to mentally or verbally interpret my test from code to English. I just type out what it should do and what state it should be in and the RSpec specification takes over from there.

It’s true that you can write a test called “test_that_name_setter_assigns_a_value_to_user” but my eyes and mind more readily interpret spaces. Furthermore, the output from RSpec tells you “User should assign a value to the name when the setter is called and return it when the getter is called.”

Second, I don’t have to specify the message for each assertion. In the Test::Unit example, each assertion was given a message so I would know what the problem was. Generally, I’m more interested in which area of functionality I broke and where I should go to fix it. RSpec tells me which assertion failed and in which area of functionality it failed.

Third, you don’t have to monkey around with Cucumber to make RSpec work. You can use Test::Unit with Cucumber, but it takes a little bit of patchwork.

Overall, for me it just comes down to pretty tests and the natural flow of the RSpec tests. I’m comfortable with Test::Unit’s capabilities, but Ruby has spoiled me into thinking that I need a test framework that’s as natural to me as the Ruby programming language itself.

[poll id="3"]

  • http://blog.davidchelimsky.net David Chelimsky

    Hey Charles,

    Thanks for posting this. I’m glad you like and use RSpec. But Jim’s article, and a lot has changed since then. It’s not just semantics anymore.

    Consider pending examples, easily customizable output formatters, nested example groups for improved structure, and component isolation in rspec-rails, etc, etc. These are all things that impact the process of doing TDD much more than the satisfying feeling one gets writing prettier tests. I like that satisfying feeling too, but that’s really only scratching the surface of what RSpec has to offer.

    Also – small typo: replace define with describe.

    Cheers,
    David

    • http://charlesmaxwood.com Chuck

      David,

      Thanks for the feedback. Is there a good source for picking up on some of those things? Feel free to post some links or email me so that I can do so.

  • http://blog.davidchelimsky.net David Chelimsky
  • victor piousbox

    “the way in which you write the tests—the semantics—is the primary difference between the two.”

    Um, semantics is the meaning, not the way of expression. So they differ in style and equal in semantics. I think.

    Good post ;-)

Previous post:

Next post: