Ruby on Rails Testing – Are RSpec and Cucumber Worth It?

cucumberruby-on-railstestingunit testing

I know most RoR programmers are testing addicts and I understand the advantages of a large testing suite but when I start testing, I never get such a large suite and I always wonder "Am I testing the right way? Are there really efficient?". I'm often dealing with integration tests testing only the way the application behave.

First, is testing really worth it? I mean, is the time spent on writing tests really worth it?

Then, I use RSpec, I've recently discovered Cucumber, used it for a while but I don't know if writing all these steps is really worth the trouble? I know I can reuse steps but I never know if these steps are too complete or not: For instance, I've been using a Given I am logged in as (.+) but I don't know if I must say in its definition Given there's a user called $1 because it can duplicate the user if ever created but that's not worthwhile always having a step before Given I am logged in as (.+). It's quite a lot of code that will maybe rarely be useful. I guess there are not new bugs on the parts tested every day…
So is Cucumber really worthwhile compared to RSpec?

Best Answer

My 'ah-ha!' moments about testing in Ruby and Rails came when I really sat down and read the definitive resources on the subject, the Rspec and Cucumber books. I shared your initial disdain of Cucumber, but then I realized that I was looking at the picture from quite the wrong angle.

Basically, Cucumber is about BDD (behaviour driven development) - you use Cucumber to plan your features, what you're going to work on next. Hmm, next you want users to be able to promote posts on a forum or something (to steal an example ;)) So you write something simple.

Given I am logged in
And I can see the post "BDD is awesome"
When I vote the post up
Then the post should have one more vote
And the page should show a message thanking me for my vote.

Note that there's no references to anything code related in there pretty much. That comes in your steps. When you refactor your code, you might have to change your step definitions, but the behaviour (your feature) will never need to change.

Now every time you run your Cucumber feature, you'll pretty much be led through how to test the feature using TDD (test driven development). This is done at a lower level using RSpec.

First run - my first step definition is undefined. Copy the block to define it in say user_steps.rb or even session_steps.rb because it relates to users and their sessions. Now, how do you define that a user is logged in? You can take them through the login process.

Given /^I am logged in$/ do
  visit login_path
  fill_in :name, :with => 'Joe'
  fill_in :password, :with => 'Password'
  click_button 'submit'
end

Should be all happy. Second step.

Given /^I can see the post "(.+)"$/ do |name|
  visit post_path(Post.find_by_name(name))
end

Again pretty easy. Note that if we totally redo our login process, or how our posts are defined and shown, we don't have to change the behaviour. Third step.

When /^I vote the post up$/ do
  pending 
end 

Here's where you're starting to talk about new functionality, but you don't quite know how it's going to work yet. How do you vote a post up? You might click an image of a +1 or something, which does an ajax post to a controller, which returns JSON, or some such. So now you can move into pure Rspec testing.

  • Test your view to make sure the +1 image is displayed,
  • Test your controller that it behaves correctly when it receives a given ajax request of the right format (both the happy and unhappy paths - what if an invalid post ID is received? What happens if the user has used up their 25 upvotes in a day? Does it increment the number of votes correctly?)
  • Test your javascript that it responds correctly when given a blob of JSON in the right format (does it update the +1 image to show it's been used? (thinking of Google+ here...) Does it show the thank you message? etc.)

All of this doesn't affect the behaviour - but when you're finished dealing with the lower level testing, it will be trivial to fill in the step definition for how to vote a post up. It might be as simple as click_link '+1'. And the rest of the steps are testing results, which again should be straightforward to do. And when you're done, then you know your feature is complete and finished. If the necessary behaviour changes, you can tweak your feature, else you can tweak your implementation code in perfect safety.

I hope this makes sense. It's all been off the top of my head, but I think it demonstrates the difference between BDD and TDD, and why Cucumber and RSpec serve different needs.

Related Topic