Rss Feed Tweeter button Facebook button Technorati button Reddit button Linkedin button Webonews button Delicious button Digg button Flickr button Stumbleupon button Newsvine button

A Waage Blog

Ruby, Rails, Life

RSpec Request Spec to Test Rails / Grape API Functionality

with 8 comments

I finally got around to trying Grape – a “RESTful API microframework built to easily and quickly produce APIs for Ruby-based web applications”. This is a project still in baby stages, but has a lot of potential and worth exploring for anyone creating a Rack-based API in Ruby, not necessarily Rails!

Now, after creating a pretty basic API that used HTTP Basic Authentication, I was inclined to write some RSpec tests to make sure my API was working the way I thought it was (.. or because I am obsessed with well-tested, beautiful code..).

After some thought, I decided that the best way to test my API was with RSpec “request” specs. Now, if you are at all relatively new to RSpec (I was a Test::Unit kinda guy before), it might not be completely obvious that “request specs” are basically what I have come to know as “integration tests”, testing high-level functionality that spans multiple controllers and multiple requests – (think: a user’s interaction with the app).

My reasoning for choosing request specs is because I want to test specific API URL endpoints routed the way I expected. (Routing is handled magically by Grape with a simple mount in the config/routes.rb file). API testing just kinda makes sense to handle in request specs.

Anyways, I ran into a couple issues because in REQUEST specs, you do not have access to the @request object (haha?), as you do in controller specs. Now, in order to mock HTTP Basic Authentication, you need to mock the request object to send headers along with the GET request.

Well, solution: It turns out you can pass headers into your get() method! I only wish I had discovered that an hour ago!

Here’s a simple excerpt from my API request specs that shows how to mock the HTTP basic authentication and test your API functionality:

With NO basic auth, it’s just a simple GET request

  it 'should return a 401 with no basic auth to /api/v1/rewards' do
    get '/api/v1/rewards'
    response.code.should == '401'
    response.body.should == "Unauthorized - Please check your username and password"

To mock the basic auth, simply pass header hash as argument to the GET request! No need to access the request object here.

  it 'should return a 200 with valid basic auth to /api/v1/rewards' do
    # Uses basic_auth helper method
    credentials = basic_auth('testuser','test')
    get '/api/v1/rewards', nil, {'HTTP_AUTHORIZATION' =>  credentials }
    response.code.should == '200'
    response.body.should == "..."

# You can define this at the bottom of your spec file, or in spec_helper for convenience
def basic_auth(user, password)
  ActionController::HttpAuthentication::Basic.encode_credentials user, password

Hope this helps someone else. Now go write some request specs! :)

Written by Andrew Waage

May 26th, 2011 at 1:29 am

8 Responses to 'RSpec Request Spec to Test Rails / Grape API Functionality'

Subscribe to comments with RSS or TrackBack to 'RSpec Request Spec to Test Rails / Grape API Functionality'.

  1. Just what I was looking for. I was able to dump using curl and the tests are quite a bit faster. Thanks!


    18 Oct 11 at 4:17 pm

  2. Outstanding! Now if someone could just point me to appropriate doc and/or explain what that ‘nil’ second parameter is for? I’m pretty aggressive about using the right tool for a job (like display specs). This, of course, implies that I have to know _how_ to use the tool in question fully…

    Jeff Dickey

    13 Feb 12 at 9:11 pm

  3. @jeff – check out this doc here for the get request:

    You can see here that the 2nd parameter is the GET parameters. In my example, I am not passing any parameters, so I pass in ‘nil’. Hope that helps!

    Andrew Waage

    13 Feb 12 at 11:08 pm

  4. @Andrew: Thanks a lot for the quick pointer! What I’m working on now is going to need both params _and_ headers, alas, so this does help a lot.

    Jeff Dickey

    13 Feb 12 at 11:58 pm

  5. Thanks a lot, it helped me to :)


    14 Jun 12 at 2:33 pm

  6. I’ve made a module to handle cases like this


    2 Oct 12 at 10:36 am

  7. @Fabio, This is great, thanks for posting!

    Andrew Waage

    2 Oct 12 at 11:13 am

  8. Exactly what I needed, thanks for posting :)

    Laura Eck

    14 Apr 14 at 6:28 am

Leave a Reply