Skip to content

Instantly share code, notes, and snippets.

@alex-zige
Last active June 8, 2023 07:49
Show Gist options
  • Save alex-zige/5795358 to your computer and use it in GitHub Desktop.
Save alex-zige/5795358 to your computer and use it in GitHub Desktop.
Rails Rspec API 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 before_each or before_all 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
@andyw8
Copy link

andyw8 commented Apr 28, 2015

I assume Rake::Test::Methods is supposed to be Rack::Test::Methods? (used in several places).

@tylercollier
Copy link

I agree with andyw8's comments about Rack vs Rake.

@mdkalish
Copy link

mdkalish commented Oct 9, 2015

Did you even test code you put in this gist?

@jgonzalezd
Copy link

@mdkalish, I dont think so get "/api/v1/items/1",:formate =>:json

@zx1986
Copy link

zx1986 commented Jun 29, 2017

In https://gist.github.com/alex-zige/5795358#enable-spec_helper-supports
It should be Rails.root.join("spec/supports/**/*.rb") ?

@Victorcorcos
Copy link

Victorcorcos commented Dec 23, 2022

What if we are NOT using Rails?

These commands are failing:

1. Rails.application 🚫

So we cannot use this:

@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

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

So we cannot use this

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment