Last Updated: March 06, 2018
·
7.079K
· alex-zige

Rails Rspec APIs Testing Notes

Rails Rspec APIs Testing Notes

Folders Structure

spec
|--- apis #do not put into controllers folder. 
      |--- your_api_test_spec.rb  
|--- controllers
|--- models
|--- factories
|--- views
|--- helpers
|--- supports
      |--- api_helper.rb
      |--- authentication_helper.rb
|--- spec_helper.rb

*note: do not put your apis folder underneath controllers folder, otherwise, it will inherited with controller ActionController::TestCase::Behavior, Rake::Test::Methods cannot be apply accordingly.

Custom Rspec Helper for Rake::Test::Methods for api scopes.

@spec/supports/api_helper.rb


module ApiHelper
  include Rack::Test::Methods

  def app
    Rails.application
  end
end

RSpec.configure do |config|
  config.include ApiHelper, :type=>:api #apply to all spec for apis folder
end

Enable Spec_helper supports

@spec/spec_helper.rb
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

API Test Spec

make sure your sample test group has type: api, then it will include Rake::Test::Methods for (get,post,put,delete) requests

@spec/apis/authentication_spec.rb

require "spec_helper"

describe "API authentication" , :type => :api do

  let!(:user) { FactoryGirl.create(:user) }

  it "making a request without cookie token " do
    get "/api/v1/items/1",:formate =>:json
    last_response.status.should eql(401)
    error = {:error=>'You need to sign in or sign up before continuing.'}
    last_response.body.should  eql(error.to_json)
  end

end  

ActionController::TestCase::Behavior v.s. Rack::Test::Methods

Rspec-Rails includes ActionController::TestCase::Behavior for simulating controller requests.

so you could do


require "spec_helper"

describe Api::V1::SessionsController , :type => :api do

  let!(:user) { FactoryGirl.create(:user) }

  it "making a request without cookie token " do
    get :index
    response.status.should eql(401)
    error = {:error=>'You need to sign in or sign up before continuing.'}
    response.body.should  eql(error.to_json)
  end

end  

Points of differents:

  • Rake::Test::Methods could query the url "/api/v1/xxxx", but ActionController::TestCase::Behavior only execute actions within current controller scope.
  • the reponse in Rake::Test::Methods called: last_response, in ActionController::TestCase::Behavior called: response.

*Notes, if you change your spec/apis folder to api, you will find out the last_repsonse is not working any more. That's because the :type=> :api scope got mixed with default ActionController behavior.

A Step Further

Reusable Sign in Helper.

@spec/supports/authentication_helper.rb

module AuthenticationHelper
  def sign_in_as_a_valid_user
      @user ||= FactoryGirl.create(:user)
      @user.reset_authentication_token! unless @user.authentication_token
      set_cookie "authentication_token=#{@user.authentication_token}"
    end
end

RSpec.configure do |config|
  config.include AuthenticationHelper, :type=>:api
end

*Notes: The Example above used token based cookie authentication. So you could change to base-authen or token-based auth based on your own needs.

Created a signed in user in your Test

use beforeeach or beforeall block or include the helper method into your assertion block

require "spec_helper"

describe "API Items Controller", :type => :api do

  before :each do
    sign_in_as_a_valid_user
  end

  it "fetch all items" do
  #or include the helper method here
  sign_in_as_a_valid_user
  ...
  end
end