Reputation: 13886
I'm writing an app with Rails that will have REST API. Most of the controllers aren't accessible unless a user has been authorized. It's done by inserting a method that checks user's privilege in before_action
hooks in controllers. I want to test that unauthorized users can not access certain parts of the API. Currently I do it like that:
require 'rails_helper'
RSpec.describe RoomsController, type: :controller do
...
describe "while unauthenticated" do
before do
logout
end
def expect_unauth
expect(response).to have_http_status(:unauthorized)
end
it "GET #index returns http unauthorized" do get :index; expect_unauth end
it "GET #show returns http unauthorized" do get :show, {id: 1}; expect_unauth end
it "DELETE #destroy returns http unauthorized" do delete :destroy, {id: 1}; expect_unauth end
it "POST #create returns http unauthorized" do post :create, {id: 1}; expect_unauth end
it "PUT #update returns http unauthorized" do put :update, {id: 1}; expect_unauth end
end
It works, but it's pretty much the same for every controller. How can I make such a test without copy-pasting this code in every controller? Should I even test for it or since it's a pretty simple I should just assume that it works and write tests for a specific to controller functionality?
Also, does it even belong in controller specs? Maybe it should be a request spec?
Upvotes: 1
Views: 325
Reputation: 3786
Why do you need to test expect_unauth on every single controller action?
I'm assuming you have the auth check in ApplicationController or somewhere common to all controllers. I.e., all API actions requiring authentication respond the same way when there's an unauthorized access. So, it's redundant to test that on every single action. You could write a single spec to test that an unauthorized access to the system responds as expected.
In the examples where the functionality of the action is being tested, the system first checks to ensure that there is a valid login, and if there isn't, the next expectation in your test will fail.
To answer the question of should you be using controller specs or request specs, take a look at rspec_api_documentation. It combines request specs with a documentation generator.
If that's overkill for you, then I think for API testing it's a fine line between a controller spec and a request spec. Controller specs stub the view, so if you want to check something in the actual response, e.g., that the JSON has something specific in it, then you would use request specs.
Upvotes: 1
Reputation: 3371
I usually had this code for the same behavior :
ACTIONS = [
[ :index, :get, {} ],
[ :show, :get, { :id => 1 }],
[ :delete, :destroy, { :id => 1 }]
]
ACTIONS.each do |action, method, params|
it "shout return unauthorized when #{method} #{action}" do
send(method, action, params)
expect_unauth
end
end
Upvotes: 1