RSpec Rails doesn't render Rails views by default

If you are using RSpec and RSpec Rails to test your Rails application, I strongly encourage you to keep reading this post because there's a gotcha in the default configuration you might not expect, especially if you ever used the default Rails test framework before.

A couple of days ago I was notified about a but in a Rails application. The application crashed when trying to create a new record.

I changed the new action the day before, but I was sure all the tests passed and the action was covered with a pretty reasonable RSpec test suite. Moreover, the action method was one of the most simplest methods I have ever written.

def new
  @record = Model.new
end

I run the test suite, all green. I executed the page in the browser, it crashed.

"My face when I discovered all tests passed but the action kept crashing."

After several minutes of debugging I discovered the culprit: RSpec (actually the RSpec Rails gem) doesn't render the content of the action by default, like the common Rails functional tests do. In fact, @response.body always resulted in an empty string.

The view contained a statement like the following

<%= f.collection_select Model.all, :id, :name %>

that was misspelled and crashed when the template was rendered. But because RSpec doesn't render the Rails views, the view was not covered by the tests at all.

The solution is simple and is called render_views.

To tell a controller to render the content of the view, simply call render_views.

require "spec_helper"

describe RecordsController do
  render_views

  describe "GET index" do
    # ...
  end
end

You can also enable render_views globally, in your spec_helper.rb file.

RSpec.configure do |config|
  config.render_views
end

The reason behind this choice is because RSpec Rails actually provides a special RSpec group called "view specs".

describe "events/index.html.erb" do
  it "renders _event partial for each event" do
    assign(:events, [stub_model(Event), stub_model(Event)])
    render
    view.should render_template(:partial => "_event", :count => 2)
  end
end

According to the documentation, this is the right way to test Rails templates in RSpec. Honestly, I never really liked this feature and I tend to keep using controller specs — the RSpec equivalent of functional tests — (or alternative test tools) to test the views.