Monday, July 7, 2008

Quick How to start with RSpec Story Runner on Rails

Writing stories is a new awesome way to do integration testing on rails.
If you have not read about that yet, check this out before you procede - http://rspec.info/

Now let's try creating a simple story and run it with a new application.

1. create a new rails application (rails 2.0.2)

$rails storyapp


2. Install Rspec - see installation details at http://github.com/dchelimsky/rspec-rails/wikis/home
for rails 2.0.2 do the following:

cd vendor/plugins
git clone git://github.com/dchelimsky/rspec.git
git clone git://github.com/dchelimsky/rspec-rails.git
cd ../../
script/generate rspec


You will get:
$ script/generate rspec
create spec
create spec/spec_helper.rb
create spec/spec.opts
create spec/rcov.opts
create script/spec_server
create script/spec
create lib/tasks/rspec.rake
create stories
create stories/all.rb
create stories/helper.rb


3. Create directory structure for your stories:
$ mkdir stories/steps
$ mkdir stories/stories


4. Patch your stories/helper.rb to:

# stories/helper.rb
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'spec/rails/story_adapter'
Dir['stories/steps/**/*.rb'].each do |steps_file|
require steps_file
end


6. If you use Textmate install RSpec bundle for Textmate:
http://blog.emson.co.uk/2008/06/installing-the-latest-rspec-textmate-bundle/

cd /Applications/TextMate.app/Contents/SharedSupport/Bundles
git clone git://github.com/dchelimsky/rspec-tmbundle.git RSpec.tmbundle


Reload your bundles in Textmate - Bundles > Bundle Editor > Reload Bundles

Install rspec story syntax from here - http://www.movesonrails.com/articles/2007/11/06/rspec-plain-text-stories

7. Create a plain text story - stories/stories/create_course/new_course
Story: Creating a new course
As an admin
I want to create a new course
So that I can get subscribers and earn money

Scenario: admin is creating a new course
Given No courses in the system

When User creates a new course 'Test'
Then The course Test appears on the home page in the courses list
And The course Test appears in the list of courses on the admin home page
end
end


8. Create ruby script to run the story - stories/stories/create_course/new_course.rb

require File.join(File.dirname(__FILE__), "../../helper")

with_steps_for :new_course do
run File.expand_path(__FILE__).gsub(".rb",""), :type => RailsStory
end


9. Run your story - $ruby stories/stories/create_course/new_course.rb

You will see:

$ ruby stories/stories/create_course/new_course.rb
Running 1 scenarios

Story: Creating a new course

As an admin
I want to create a new course
So that I can get subscribers and earn money

Scenario: admin is creating a new course

Given No courses in the system (PENDING)

When User creates a new course 'Test' (PENDING)

Then The course 'Test' appears on the home page in the courses list (PENDING)
And The course 'Test' appears in the list of courses on the admin home page
end
end (PENDING)

1 scenarios: 0 succeeded, 0 failed, 1 pending

Pending Steps:
1) Creating a new course (admin is creating a new course): No courses in the system
2) Creating a new course (admin is creating a new course): User creates a new course 'Test'
3) Creating a new course (admin is creating a new course): The course 'Test' appears on the home page in the courses list
4) Creating a new course (admin is creating a new course): The course 'Test' appears in the list of courses on the admin home page
end
end


10. Create stories/steps/new_course_steps.rb

steps_for(:new_course) do
Given "No courses in the system" do
Course.count(:all).should == 0
end

When "User creates a new course '$title'" do |title|
post_via_redirect '/courses', :name => title, :description => "Course description"
response.should be_success
end

Then "The course $title appears on the home page in the courses list" do |title|
get '/'
response.should have_text(title)
end

Then "The course $title appears in the list of courses on the admin home page" do |title|
end
end


now if you run $ ruby stories/stories/create_course/new_course.rb
or ruby stories/all.rb
you will get:

Running 1 scenarios

Story: Creating a new course

As an admin
I want to create a new course
So that I can get subscribers and earn money

Scenario: admin is creating a new course

Given No courses in the system (FAILED)

When User creates a new course 'Test' (SKIPPED)

Then The course Test appears on the home page in the courses list (SKIPPED)
And The course Test appears in the list of courses on the admin home page
end
end (PENDING)

1 scenarios: 0 succeeded, 1 failed, 0 pending

Pending Steps:
1) Creating a new course (admin is creating a new course): The course Test appears in the list of courses on the admin home page
end
end

FAILURES:
1) Creating a new course (admin is creating a new course) FAILED
NameError: uninitialized constant Course
/Library/Ruby/Gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:266:in `load_missing_constant'
/Library/Ruby/Gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:453:in `const_missing'
/Library/Ruby/Gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:465:in `const_missing'
./stories/steps/new_course_steps.rb:3:in `No courses in the system'
stories/all.rb:2

What you have now is a sample story with some steps. Of course there is no functionality there - models and controllers and your specs fail. But that's the starting point to get to writing the application  code itself. And from the story and steps we see that what we need here to make the story pass is  the Course model, course controller with create action, home page that shows courses and admin home page that also shows courses but for admin.

Happy storytelling...

Links for further reading:

1. http://rspec.info/
2. http://www.benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-in-user-stories/
3. http://www.brynary.com/bdd
4. http://www.vaporbase.com/postings/Getting_Started_with_Story_Runner

No comments: