Twitter GitHub Facebook Instagram dirv.me

Daniel Irvine on building software

Parameterized RSpec shared examples

13 August 2014

Specification-based test frameworks like RSpec revolve around examples, essentially short specifications by example. Each test context--usually a class--has a number of examples associated it. An RSpec example looks like this:

describe FooController do
  it 'responds to a generate request' do
    get :generate
    expect(response.status).to eq 200
    expect(response).to render_template(:foo_view)
  end
end

Often, it’s desirable to share examples between multiple contexts: when testing a group of subclasses with a common base class, each subclass will generally maintain its own test context (in RSpec, each class has its own spec file). But since each subclass shares common functionality, these test contexts will end up containing repeated examples.

describe BarController do
  it 'responds to a generate request' do
    get :generate
    expect(response.status).to eq 200
    expect(response).to render_template(:bar_view)
  end
end

RSpec shared examples are a common way to re-use examples across multiple test contexts. But in the example above, how do we deal with the symbol passed to render_template which differs in each controller? FooController passes :foo_view while BarController passes :bar_view.

Simple. We use a parameterized shared example, which looks like this:

shared_examples 'generate' do |view|
  it 'responds to a generate request' do
    get :generate
    expect(response.status).to eq 200
    expect(response).to render_template(:view)
  end
end

describe FooController do
  include_examples 'generate', :foo_view
end

describe BarController do
  include_examples 'generate', :bar_view
end

About the author

Daniel Irvine is a software craftsman at 8th Light, based in London. These days he prefers to code in Clojure and Ruby, despite having been a C++ and C# developer for the majority of his career.

For a longer bio please see danielirvine.com. To contact Daniel, send a tweet to @d_ir or use the comments section below.

Twitter GitHub Facebook Instagram dirv.me