[Updated for 0.9 on 2007/04/12]

rspec-0.9’s ’spec/rails’ (RSpec on Rails) plugin lets you spec your views in complete isolation of any controllers. This means that you can spec your views even before there are any models or controllers! Once models and controllers do exist, changes to them will not cause your view specs to fail.

Here’s a brief tutorial to get you started.

Create a new rails app.

rails oldnews

Now install rspec and rspec_on_rails plugins.

cd oldnews
ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/REL_0_9_0_BETA_2/rspec
ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/REL_0_9_0_BETA_2/rspec_on_rails
ruby script/generate rspec

Next, using the rspec controller generator, create a controller for articles:

$ script/generate rspec_controller  articles list show
     exists  app/controllers/
     exists  app/helpers/
     create  app/views/articles
     create  spec/controllers/
     create  spec/helpers/
     create  spec/views/articles
     create  spec/controllers/articles_controller_spec.rb
     create  spec/helpers/articles_helper_spec.rb
     create  app/controllers/articles_controller.rb
     create  app/helpers/articles_helper.rb
     create  spec/views/articles/list_view_spec.rb
     create  app/views/articles/list.rhtml
     create  spec/views/articles/show_view_spec.rb
     create  app/views/articles/show.rhtml

Open up spec/views/articles/list_view_spec.rb and update it as follows:

require File.dirname(__FILE__) + '/../../spec_helper'
 
describe "articles/list with just one article" do
  it "should display the title" do
    render 'articles/list'
    response.should have_tag('div', "example title")
  end
end

Now run the specs – stand in the project root and …

ruby spec/views/articles/list_view_spec.rb -fs

… and you should get output like this (plus some backtrace info) …

articles/list with just one article
- should display the title (FAILED - 1)

1)
'articles/list with just one article should display the title' FAILED
Expected at least 1 elements, found 0.
<false> is not true.

Open up app/views/articles/list.rhtml and edit as follows…

example title

Run the spec again and you’ll see that it passes. We have duplication between the spec and the subject code. To get rid of it, we’ll have to feed the view some data that it can display. Add a setup to the spec:

require File.dirname(__FILE__) + '/../../spec_helper'
 
describe "articles/list with just one article" do
  before do
    @article = mock("article")
    @article.should_receive(:title).and_return("example title")
    assigns[:articles] = [@article]
  end
  it "should display the title" do
    render 'articles/list'
    response.should have_tag('div', "example title")
  end
end

… and run the specs …

articles/list with just one article
- should display the title (ERROR - 1)

1)
Spec::Mocks::MockExpectationError in 'articles/list with just one article should display the title'
Mock 'article' expected :title with (any args) once, but received it 0 times

This fails because the mock article never receives the :title message. You can get this to pass like so …

# in app/views/articles/list.rhtml
<%= @articles[0].title %>

So we’re part of the way there, but what we want is for the view to iterate through the list. So add another spec …

describe "articles/list with three articles" do
  before do
    articles = (1..3).inject([]) do |list, index|
      article = mock("article #{index}")
      article.should_receive(:title).and_return("example title #{index}")
      list << article
    end
    assigns[:articles] = articles
  end
  it "should display the title" do
    render 'articles/list'
    response.should have_tag("div", "example title 1")
    response.should have_tag("div", "example title 2")
    response.should have_tag("div", "example title 3")
  end
end

… which produces …

$ ruby spec/views/articles/list_view_spec.rb -fs

articles/list with just one article
- should display the title

articles/list with three articles
- should display the title (FAILED - 1)

1)
'articles/list with three articles should display the title' FAILED
<"example title 2"> expected but was
<"example title 1">.

It is failing on the second title because we’re not yet iterating through the articles. So…

<% for article in @articles %>
<div><%= article.title %></div>
<% end %>

… and viola!

$ ruby spec/views/articles/list_view_spec.rb -fs

articles/list with just one article
- should display the title

articles/list with three articles
- should display the title

As you can see, we are able to do this without any models or actions yet developed. As those get added, this spec will continue to pass because there is no dependency between it and the real models and controllers.

Now the risk here is that you could build a model that doesn’t have a title field in it and your app will blow up! Admittedly, if you only write isolated, granular specs like this that risk is real. So you should be doing this in conjunction with integration testing. Unfortunately, RSpec 0.9 does not yet support any integration testing directly, but there are plenty of great tools that will handle that for you. If you want to keep it on the command line, use something like rails integration testing. If you like in-browser testing you can use watir or selenium.

12 Responses to “tutorial - driving view behaviour with ’spec/rails’”

  1. piyush Says:

    i have installed gem for rspec. but when i go for installing rspec plugin then its not found and name occur. and after that if i try ruby script/generate rspec then i says that it couldn’t find rspec generator.

    i am using ruby185-22_rc2.exe and rails gem 0.7.5.1. so reply me if anyone know solution for this.

  2. David Chelimsky Says:

    It is and I’ve not heard that problem reported yet. If it persists, please report a bug to the tracker:

    http://rubyforge.org/tracker/?group_id=797

    Thanks for checking out rspec!

  3. mitjok Says:

    for rspec 0.7.5.1 used: svn://rubyforge.org/var/svn/rspec/tags/REL_0_7_5_1/rspec_on_rails/vendor/plugins/rspec_on_rails on edge rails and Rails 1.1.6 installed as gem

  4. sinasi Says:

    I am trying to learn rails.

    I’ve installed rspec fine (rspec 0.7.5.1). I’ve then insalled the rspec plugin. But, when I run “ruby script/generate rspec, I get the “Couldn’t find ‘rspec’ generator” message. I have rails 1.2.1 installed.

    Is rspec 0.7.5.1 compatible with rails 1.2.1?

    Thanks

  5. anon Says:

    Yeah, they’ve definitely got the wrong svn repo on the rspec site… or at least they changed the location.. welcome to rails

  6. anon Says:

    Yeah, they’ve definitely got the wrong svn repo on the rspec site… or at least they changed the location.. welcome to rails

  7. Danny Says:

    apparently I’m suffering from dyslexia too? it works now I’ve copy paste your svn path

    svn://rubyforge.org/var/svn/rspec/tags/REL_0_7_5/vendor /rspec_on_rails/vendor/plugins/rspec_on_rails

    svn://rubyforge.org/var/svn/rspec/tags/REL_0_7_5 /rspec_on_rails/vendor/plugins/rspec_on_rails

    the top one is the one from the tutorials on the net (i copy paste it just now from up at this page) The lower one is the one you just gave me, maybe update? :p

    thanks a lot though!!

  8. Danny Says:

    Yes that is what I’m using, I checked… very strange, I’m trying to find on the net what I am doing wrong…

  9. Danny Says:

    hmz I am getting the same problem as Jordan, except I’ve checked and doubble checked the svn path and it seems I am doing everything alright.

    RSPEC_0_7_5 on rails 1.1.6

    any thoughts?

  10. David Chelimsky Says:

    Danny – the path should be this:

    svn://rubyforge.org/var/svn/rspec/tags/REL_0_7_5/rspec_on_rails/vendor/plugins/rspec_on_rails

    Is that what you’re using?

  11. Jordan Arentsen Says:

    Heh, I’m sorry. I figured out my problem. My apparent dyslexia got me, and i completely messed up the subversion path. Thanks again.

  12. Jordan Arentsen Says:

    Hey,

    I really enjoy your blog. I’m trying to do this who RSpec thing, but I’m running into issues, and you’re the only one who seems to be running 0.7.5. RSpec installs fine, but then when I try it install the rails plugin, weird stuff happens. Any ideas?

    blissdev:~/code/rails/client/wordone > ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/REL_0_7_5/vend
    or/rspec_on_rails/vendor/plugins/rspec_on_rails
    Export complete.
    blissdev:~/code/rails/client/wordone > ruby script/generate rspec
    Couldn't find 'rspec' generator