tags:

views:

55

answers:

1

I'm implementing a service that has several different ways it can be accessed:

  • Using simple query parameters
  • With parameters encoded as a Javascript object

For some calls both GET and POST are supported, with POST being used when there is large amounts of data being sent to the service.

What's the best way to structure my RSpec tests to avoid unnecessarily repeating code, allowing me to run the same basic assertions each time?

I'm already using shared_examples to capture some comment tests for things like response code, mimetype, etc. But I'm wondering whether there are other options, particularly when I want to invoke the service using all request methods AND a range of expected inputs and outputs.

+1  A: 

The way I would do it in this case is to specify the request as a lambda that performs it. That way I can refer to it in my shared specs and set a different one for each type of request.

I like using rspec describe blocks when its sets an expectation, in this case that a particular request method is used. The whole thing will look something like this:

describe FooController do
  shared_examples_for "any request" do
    it "assigns foo" do
      @request.call
      assigns[:foo].should ==  "bar"
    end

    it "does not change the number of bars" do
      @request.should_not change(Bar, :count)
    end
  end

  context "using GET" do
    before do
      @request = lambda { get "index" }
    end

    it_should_behave_like "any request"
  end
end

An even cleaner way is to use the 'let' construct, although it may be a step too deep in rSpec magic for a novice:

describe FooController do
  shared_examples_for "any request" do
    it "assigns foo" do
      request.call
      assigns[:foo].should ==  "bar"
    end

    it "does not change the number of bars" do
      request.should_not change(Bar, :count)
    end
  end

  context "using GET" do
    let(:request) { lambda { get "index" } }

    it_should_behave_like "any request"
  end
end