-
Notifications
You must be signed in to change notification settings - Fork 0
How To: Stub authentication in controller specs
These are instructions for allowing you to use resource test doubles instead of actual ActiveRecord objects for testing controllers where Devise interactions are important. This means there's even less reliance on the database for controller specs, and that means faster tests!
This approach certainly some evolution, and it's reliant on an as-yet unmerged pull request for rspec-mocks
, but it's a start.
To stub out your user for an action that expects an authenticated user, you'll want some code like this (once you've got Devise::TestHelpers
loaded):
user = double('user')
request.env['warden'].stub :authenticate! => user
controller.stub :current_user => user
And for behaviours where the user is not signed in:
request.env['warden'].stub(:authenticate!).
and_throw(:warden, {:scope => :user})
If you're paying attention, you'll see there's the scope for the given resource - adapt that as necessary (and it's especially important if you're using more than one resource scope for Devise in your app).
At the time of writing rspec-mocks
doesn't support throw parameters, so you'll need to use my patch in the meantime (alongside rspec
and rspec-rails
2.8.0.rc1).
gem 'rspec-mocks',
:git => 'git://github.com/freelancing-god/rspec-mocks',
:ref => 'aca77b2a330213b9feeb689cb29d69a8833ede50'
gem 'rspec-rails', '2.8.0.rc1'
As a more fleshed out example, I have the following in a file I've added to my app at spec/support/controller_helpers.rb
:
module ControllerHelpers
def sign_in(user = double('user'))
if user.nil?
request.env['warden'].stub(:authenticate!).
and_throw(:warden, {:scope => :user})
controller.stub :current_user => nil
else
request.env['warden'].stub :authenticate! => user
controller.stub :current_user => user
end
end
end
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.include ControllerHelpers, :type => :controller
end
And then in controller examples we can just call sign_in
to sign in as a user, or sign_in nil
for examples that have no user signed in. Here's two quick examples:
it "blocks unauthenticated access" do
sign_in nil
get :index
response.should redirect_to(new_user_session_path)
end
it "allows authenticated access" do
sign_in
get :index
response.should be_success
end