Last Updated: February 25, 2016
·
823
· benburton

Putting RSpec describe blocks in other blocks to keep DRY

Suppose you have a controller which responds to the same action on two different HTTP verbs. Something like the following is a good example:

class BlogPostsController < ApplicationController
  def update
    render nothing: true
  end
end

with the corresponding entries in routes.rb

resource :blog_posts do
  member do
    post 'update'
    put 'update'
  end
end

Normally, you could test both of these actions using two separate tests:

describe BlogPostsController do

  describe "POST update" do
    subject { post :update }
    it { should be_success }
  end

  describe "PUT update" do
    subject { put :update }
    it { should be_success }
  end

end

...but you could also abstract the HTTP verbs into an array, and test the describe in a block yielding the verb:

describe BlogPostsController do

  %w{post put}.each do |method|
    describe "update" do
      subject { send(method, :update) }
      it { should be_success }
    end
  end

end

It's also possible that you use different parameters that apply to all tests in a describe block. For example, if we had two roles that both needed permissions to execute the same actions on a route, we could also pass them in using the same process. I don't know why, but I'd never thought to put describes inside of blocks before. Clearly there are interesting possibilities.