making the world a stranger place

Site menu:

Archives

Links:

Amazon Ad

Tags

Meta

RSpec Stories On Rails

Congrats on Passing that Test SuiteUsing a story to drive your development tasks is a good idea, even when there is only 1 team member. Writing stories helps you stay focused on the requirements without getting side-tracked into something that isn’t working toward the end goal of your app. There’s always time for script.aculo.us later! Using RSpec stories also means you have tests to run against your code so you know that fixing something probably didn’t break something else.

First thing you want to do is get the RSpec on Rails plugin installed, and generate the RSpec code.

$ ./script/plugin install git://github.com/dchelimsky/rspec.git
$ ./script/plugin install git://github.com/dchelimsky/rspec-rails.git
$ ./script/generate rspec

Stories are broken down into 2.5 files:

  • 1. The Story file - Where the plain text story resides
  • 2. The Step file - Where the different steps in your story are defined.
  • 2.5 The Story runner file - The ruby code that kicks everything off.

First off, the story file is a semi-plain text description of some stuff that happens in your application, and follows this basic format:

Story: <Description of Story>
As a <Whoever is doing the actions>
I want to <What you want to do>
So I can <Why you want to do it>

Scenario: <Description of a Scenario that could happen>
Given <Something>
When <Something happens>
Then <What is the expected result>

Scenario: <Description of a Scenario that could happen>
Given <Something>
When <Something happens>
Then <What is the expected result>

Not exactly conversational English, but no crazy ||’s &&’s or ==’s that would scare normal customers away. The top of the story is there to give you a general overview of what’s being tested. In each story, you’ll have different scenarios, mini-stories if you will, that cover a complete set of actions that can take place.

In each Scenario there are three basic statements in which you describe what state the application is in and the assumptions about the outside world, the actions that are taken, and the expected result. So, for a user regestering for the first time, you are assuming that the user has a username and password picked out ,and an email address. That user would then enter those into your regestration form, and then when they’re submitted, he’d be wisked away to some kind of confirmation page, and that user added to the database. This file (/stories/signup_for_accounts_story) may look like:

Scenario: User fills out form correctly

Given a username ‘brittany’
And a password ‘foobar’
And an email ‘foo@bar.com’
And  there is no user with this username

When the user creates an account with username, password and email

Then there should be a user named ‘brittany’
And there should be a profile for ‘brittany’
And should redirect to users profile page

Pretty straight forward, huh? You can have as many scenarios as you need to cover whatever part of your application you’re testing. At this point, everything is still pretty magical. How does RSpec know so much about your application that it can guess method names, form paths and so on? Well….it doesn’t. That’s where the step file comes in.

The step file is where you define what all of these arbitrary lines of text should actually do. Each line is defined in a block in your steps file, which normally lives in the stories/steps folder, and looks like this

steps_for(:<what you’re doing>) do

Given “<an assumption>” do
<do something having to do with that assumption>
end

When “<an action>” do
<do that action>
end

Then “<an expected result>” do
<see if that result is what…resulted>
end

end

That’s the general layout of the steps file. You can have as many steps as you need, and they’re reused between scenarios. Your Given blocks will usually do something like mock a model, assign a value to a variable, or stub an outside service. These lay the basis for your assumptions for the state of being before your action is excuted. When blocks execute actions, such as posting to a web form. Finally, Then describes the expected state of your application after the action is executed. These are where you’ll usually find out where your application is broken. In pratice, this (/stories/steps/signup_for_accounts_steps.rb) looks like:

steps_for(:signup) do

Given “a username ‘$username’” do |username|
@username = username
end

Given “a password ‘$password’” do |password|
@password = password
end

Given “a password_confirmation ‘$pass_conf’” do |pass_conf|
@password_confirmation = pass_conf
end

Given “an email ‘$email’” do |email|
@email = email
end

Given “there is no user with this username” do
User.find_by_login(@username).should be_nil
end

When “the user creates an account with username, password and email ” do
post “/users”, :user => { :login => @username,
:password => @password,
:password_confirmation => @password,
:email => @email }
end

Then “there should be a user named ‘$username’” do |username|
User.find_by_login(username).should_not be_nil
end

Then “there should be a profile for ‘$username’” do |username|
user = User.find_by_login(username)
user.should_not be_nil
Profile.find_by_user_id(user.id).should_not be_nil
end

Then “And should redirect to users profile page” do
user = User.find_by_login(@username)
user.should_not be_nil
response.should redirect_to(user)
end

end

This defines all the actions that we need to run our story. Kind of tedius, i know, but you can reuse blocks in other scenarios. If you notice, some blocks have a $variable, these are picked up by the RSpec story parcer and passed into the block, so it makes the blocks more flexable, and you can use them more often.

Finally, there is the half-file, the story runner, all it does is link everything you need togeather, and it (/stories/signup_for_account_story.rb) will look like this:

require File.dirname(__FILE__) + “/helper”

with_steps_for(:signup) do
run_local_story “signup_for_account”, :type => RailsStory
end

yeah, not much to it, eh? Just change the with_steps_for() symbol and the run_local_story argument and you’ll be on your way.

Now you can run your new story by typing in

$ ruby stories/signup_for_account_story.rb

and watch it make sure your app is doing what it’s supposed to do. It’ll notify you of any failures, and stop the test if it encounters them, so you can fix them right away.

There are many more, much better resources for this than mine, so if you want to check them out, here is a list of some of the better ones.

RSpec -1.1.4: Spec:: Rails

David Chelimsky: Integration Testing With Rspec’s Story Runner …

Telling stories with RSpec

evang.eli.st User stories with RSpec’s Story Runner

RSpec plain text story runner on a fresh rails app

If you find anything in here that is dumb, crappy, or just plain wrong, drop a comment and i’ll fix it so it sucks less. Thanks.

Picture Credits: jay | http://conversationswithplasticdinosaurs.com/

Tags: , , , , , ,

Write a comment