Crank your specs :redux

Jon Rogers ·

A couple months ago, Ben Lindsey wrote ‘Crank Your Specs’ which talked about how to speed up your test suite.  I’ve been chatting with him since then, and trying to figure out other ways to shave some time off our ever growing suite of tests.  Here’s a little trick I discovered that improved testing time.

We use RSpec to test both controllers and views.  View testing in the controller tests is pretty easy.  Simply add

integrate_views

in a describe block, and the response object from requests will contain a full html response.body (instead of mocking out the view creation) and send that back so you can add tests like

describe ArticlesController do
  integrate_views
  describe "#show"
    before do
      get :show, :id => articles(:nytimes).object_id
    end
    it "has a header" do
      response.should have_tag('h1')
    end
  end
end

But there are plenty of controller tests that don’t need to see the view at all.

describe ArticlesController do
  describe '#index' do
    it "fetches all the articles" do
      assigns(:articles).should == Article.all
    end
  end
end

Generating those views takes a bunch of time. And because the integrate_views keyword applies to individual describe blocks, you can specify it only where you need it, instead of at the beginning of the first describe block.

For a couple different projects, I ran through the current set of specs and removed integrate_views entirely. Then, after starting autospec, ran back through each spec file and inserted integrate_views into the nested describe blocks that needed them until i had all the controller specs passing again.

The refactored faster specs look like this:

describe ArticlesController do
  describe '#index' do
    it "fetches all the articles" do
      assigns(:articles).should == Article.all
    end
  end
  describe '#show' do
    integrate_views  # only integrate views for this block
    before do
      get :show, :id => articles(:nytimes).object_id
    end
    it "has a title" do
      response.should have_tag('h1')
    end
  end
end

Making this mod to 2 of the projects I’ve been working on resulted in the following gains:

Project 1: (Rails/ERB): ~800 specs.  171sec -> 134sec  (27% speedup)

Project 2: (Rails/Erector): ~2000 specs. 13min -> 12min (8% speedup)