I'm currently new to RSpec and trying to implement some Controller testing with RSpec
In my Rails app, I'm using Devise as my authentication system. My question is, When we test a controller which uses some authentication system (in my case Devise), what is the standard practice?
Is it
1 - to skip the authentication
or
2 - to authenticate the controller
as per the question, following is my controller
require File.dirname(__FILE__) + '/../spec_helper'
describe ProjectsController do
include Devise::TestHelpers
p "starting..."
before(:each) do
p "in before method"
#request.env["devise.mapping"] = Devise.mappings[:user]
sign_in Factory.create(:user)
end
it "should create a project" do
p "should create a project"
end
after(:each) do
#user.destroy unless #user.nil?
end
end
I can only see 'starting', But why its not going to "in before method" and "should create a project"
I'm using Rspec2 and Rails2 on Ubuntu.
Check this: Stubbing Devise in rSpec and Rails3.
Standard practice is not skipping authentication, but effectively making sure that a correct user is logged in (for devise).
Referring to your code: have you tried to create some real test? E.g. something as simple as
it "gets index" do
get :index
response.status.should be == 200
end
I am not sure why you are not seeing the print-statements. Either rspec skips the empty step (there is no real code), or because something else went wrong. But honestly, I am not even sure if using p inside rspec works.
A tool like rubymine allows you to easily debug your specs if you want to step into it (which imho is a better approach then the scattered p statements).
Related
I added an import method to a controller, and it works just fine when I test it manually from my website, but it is failing in rspec. Here is what my test looks like:
require 'spec_helper'
describe PropertiesController do
let!(:user) { FactoryGirl.create(:user) }
before :each do
sign_in user
end
describe "should upload user properties" do
before do
post :import, spreadsheet: fixture_file_upload("/files/property_upload_template.xlsx")
end
it "should have created records" do
expect(Property.count).to eq 3
# Some other assertions
end
end
end
When I add puts statements inside my import action, including on the very first line, none of them are apparently invoked. The test is generating no errors other than failing the assertions. Similarly, when I look at the test.log file, all that happens is the creation of my test user (and a devise confirmation email gets sent out), but it doesn't appear that the import action is ever hit. The test server seems to recognize the route fine, but it's not actually executing the action.
Is there something wrong with my test configuration?
I had been banging my head for a good couple hours, but I just figured it out. I needed to confirm the user in my user factory. I guess since I enabled the confirmable module in devise, and the user wasn't confirmed, it was silently not allowing me to authenticate...
... Would sure be nice if rspec/rails/devise generated some sort of error pointing me to the problem here.
For the sake of completeness, I'm adding in the code for confirming a user in the version of FactoryGirl at the time of that writing:
FactoryGirl.define do
factory :confirmed_user, :parent => :user do
after(:create) { |user| user.confirm! }
end
end
I need to check if my API method sends an email. Based on various threads on SO, i ended up with something like this:
require 'spec_helper'
describe Api::V1::IntervieweesController do
before(:each) do
#project = FactoryGirl.create(:project)
end
describe "POST /api/v1/interviewees/remind_code" do
before(:each) do
#interviewee = FactoryGirl.create(:interviewee, project: #project)
end
it "sends email with code" do
post :remind_code, interviewee: { email: #interviewee.email }
ActionMailer::Base.deliveries.last.to.should == [#interviewee.email]
end
end
end
The problem is, ActionMailer::Base.deliveries is allways nil, even if that method sends that email (when i'm running that method in a 'normal' way in my browser, outside of rspec tests). What's more interesting - it works fine in model specs. Do you have any idea what am i possibly doing wrong?
Rails v4
Ruby v2
rspec v3.0.0.beta1
Please have in mind that the controller's action i'm testing above works fine and sends that email on production/development.
I am using devise configured to use omniauth facebook sign in integration.
When calling the sign_in method from my spec/request tests I get:
undefined method `env' for nil:NilClass
spec:
describe FacebookController do
include Devise::TestHelpers
it "should display facebook logged in status" do
#user = User.create(:id => "123", :token => "token")
sign_in #user
visit facebook_path
end
end
Your code looks a lot like mine - I was trying to use Capybara and the Devise TestHelper functions, and it turns out you can't, per https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara. The recommended way to do it is explained on that page, and it worked for me.
To be clear, here's what I did - in spec_helper.rb:
RSpec.configure do |config|
config.include Warden::Test::Helpers
end
Warden.test_mode!
And in my code, simply - logout :user.
Here's why, according to the Devise wiki, you cannot use sign_out:
If you're wondering why we can't just use Devise's built in sign_in and sign_out methods, it's because these require direct access to the request object which is not available while using Capybara. To bundle the functionality of both methods together you can create a helper method.
Which, roughly, means that whereas with, say, MiniTest, an object representing the request (#request) is added as an instance variable to the test case class, that doesn't happen with Capybara. I haven't looked at the code to know the details more exactly but basically, Warden expects to find this object to then access the cookie store where the sign in credentials are. With Capybara/RSpec, I expect this isn't happening.
i've started writing tests for my controllers. For once of them, i need to be logged in, in order to check whether the page is rendered etc.
Since i'm using Devise that has a current_user helper over a User model, how can i form my :
describe "when it GETS 'town'" do
it "should render the template and be successful" do
get :index
response.should render_template(:index)
response.should be_success
end
end
so that i don't get the undefined "authenticate!" method (devise specific) error ?
There's a good writeup on this topic on the Devise wiki. Basically you need to add the Devise test helpers, then call sign_in to get a valid current user when your spec expects one.
I have an Ruby on Rails 3 admin_controller with the default set of CRUD, index and so on methods. I'd like to test each of these for certain assertions with rspec.
Like response.should render_template("layouts/some_layout") or tests that it should require login.
Copy-pasting that test into the group of tests for each method is a lot of duplication. IMO it makes little sense to have an
it 'should require login' do
Duplicated several times troughout that test.
Is there a simple way to run a test on a list of methods? Say defined_methods.each do |method| it 'should' .... of some sort?
Is this a good way in the first place? Or am I taking a wrong route in the first place?
Given that you really want all those assertions, have you considered shared example groups?
shared_examples_for "an action that requires authentication" do
it "should render successfuly" do
sign_in(user)
response.should be_success # or whatever
end
it "should deny access" do
# don't sign_in the user
# assert access was denied
end
end
shared_examples_for "another behaviour" do
# ...
end
let(:user) { create_user }
describe "#index" do
before(:each) { get :index }
it_behaves_like "an action that requires authentication"
it_behaves_like "another behaviour"
end
describe "#show" do
before(:each) { get :show }
it_behaves_like "an action that requires authentication"
end
# ...
Of course before writing large number of specs for a basic functionality you should always check if it isn't already tested by the library that is providing the functionality (e.g. checking for the rendered template, if it is handled by rails's implicit rendering, might be a bit overkill).
If you wanted to go down the route of iteratively testing each public method in the controller, you could do something like:
SomeController.public_instance_methods(false).each do |method|
it "should do something"
end
However, I think a shared example group (see about half way down this page: http://rspec.info/documentation/) would be prettier. If it were extracted so it could be used across all your controller specs, it'll be even nicer..
shared_examples_for "admin actions" do
it "should require login"
end
Then in each controller spec:
describe SomeController do
it_should_behave_like "admin actions"
end
Just add it to your test_helper.rb, something like:
def requires_login
...
end