doing it again and again

August 8, 2007 Alex Chaffee

Here’s an RSpec trick I discovered yesterday. Sometimes when you’re writing a test you want to loop over some precondition data. But if you do a loop inside your test (or spec), then all the cases will be subsumed in a single test method (or “it” block). This means you’ll have the following problems:

  • The first case to fail will cause the rest of the cases not to run. It’d be nice to see them all in a single test run.
  • You won’t take advantage of RSpec’s cool self-documenting trick of labeling each it block with a full description of the failure, and it’ll be harder to debug which case failed.
  • If you’re calling into Rails (e.g. in a View spec), you’ll only be able to call certain methods — especially render — once per test method. That means that you simply can’t use a loop inside a method to collapse redundant tests into a single block.

Ruby to the rescue! Instead of looping inside your it block, loop outside your it block.

require 'hpricot'

describe "navbar" do

  TABS = ["Home", "Articles", "Comments", "Preferences"]
  TABS.each do |tab|
    it "selects tab #{tab}" do
      assigns[:current_navbar_tab] = tab
      render "/shared/_navbar.mab"
      doc = Hpricot(response.body)
      doc.at("//li[@class=active]/a").inner_html.should == tab
    end
  end

end

When I mentioned this at standup, Nathan mentioned the eval module… maybe he or someone else can add more detail in a comment?

Note that this technique should be used sparingly. It’s kind of a test smell to have loops, but it’s useful in certain cases… In this example it’s actually different code rendering each separate tab. If we spent a bit more time and extracted a Tab object then we could possibly get away with just unit testing that class and trusting it to render properly on the page for each actual tab.

About the Author

Biography

More Content by Alex Chaffee
Previous
Advanced Proxy Usage, Part I
Advanced Proxy Usage, Part I

One of the more underutilized features of ActiveRecord is the Assocation Proxy. But they are also one of t...

Next
Cacheable Flash
Cacheable Flash

Page caching is an easy way to get massive performance and scalability increases with little up front effor...

How do you measure digital transformation?

Take the Benchmark