In a functional test, I want to call an action in another controller.
You have to set the #controller instance variable to the controller that should be used.
Example usage in a test helper method (of course you don't need to use it in a helper method - you can use it right in your test method):
def login(user_name='user', password='asdfasdf')
# save the current controller
old_controller = #controller
# use the login controller
#controller = LoginController.new # <---
# perform the actual login
post :login, user_login: user_name, user_password: password
assert_redirected_to controller: 'welcome', action: 'index'
# check the users's values in the session
assert_not_nil session[:user]
assert_equal session[:user], User.find_by_login('user')
# restore the original controller
#controller = old_controller
end
Answered by Jonathan Weiss, in 2006 on ruby-forum: post() to other controller in functional test?
It should be noted that, for the most part (probably >99.9% of the time), one should use integration tests (aka feature tests) for testing inter-controller behaviour.
Related
I have a controller file:
some_controller.rb:
class SomeController < ActionController::Base
def get_params
# Do something with params
end
end
And a helper file:
module SomeHelper
def modify_params
get_params
end
end
And rspec File for helper:
require 'spec_helper'
describe SomeHelper do
describe 'check_if_param_has_key' do
it "checks if param has key" do
modify_params.should eql(true)
end
end
Here, I am calling controller's method inside helper method. Now I am writing test cases for helper method modify_param.
But it throws error : NoMethodError: get_params
Is there a way to access controller's method inside helper spec?
Is this the right way to do it? Or Am I missing something in this?
Edited:
The controller is ApplicationController, and method inside it return string containing which controller/method was called on page load, by looking at params[:controller], params[:action]
As the author of RSpec has pointed out, helper tests are conceptually unrelated to controllers. So even if there was a way, you'd likely not want to bring the controller into the picture. You can easily stub out the method call in your spec:
describe SomeHelper do
describe "#foo" do
before do
allow(helper).to receive(:bar).and_return("hello")
end
it { expect(helper.foo).to eql("hello") }
end
end
Even if you had a controller, you'd likely have to stub the method call there, to cover the edge case.
Note that this stubbing a method not defined in the helper will fail if you're using verifying doubles.
My problem has been solved by making get request to the page:
describe 'check if the home page by checking params', :type => :request do
it 'return true if page is Home page' do
get "/homepage"
helper.modify_params.should eql(true)
end
end
In above code, after calling get request to homepage, helper method will have access to all the params and controller action it is calling. All my test cases have been passed.
I am trying to test a form that creates a new instance of a model with capybara. The problem is that the user_id is supplied by the controller in the create method and not by the form:
#contractor = Contractor.new(contractor_params.merge({user_id: current_user.id}))
Is it now possible to set user_id in my Capybara test, or set the current_user variable in my test in a way that the controller has access to it?
Yes, in your test, in a before block, stub out current_user with a created user, like so (assuming you are using FactoryGirl):
let(:user) { FactoryGirl.create(:user) }
before do
controller.stub(:current_user).and_return(user)
end
When you controller hits current_user, it will be the user you created.
I've set up a controller I'm testing so that most requests to its actions redirect to the sign_in page if a session doesn't exist.
Because of this, I need to use the sign_in method when testing controllers in a unit test. I also need to create the user in the database so they can sign in.
This is all easily achieved like this:
describe MyController, do
let(:user) { FactoryGirl.create(:user)} # The 'create' creates in the database as well as in memory
context "with session" do
before {
sign_in user
}
context ".index" do
assigns(:example).should == "Just an example"
end
end
end
However, this isn't a good unit test because it's depending on active record and the database, as well as Devise's test helper methods.
So how can I use a mock (or something) to stop my controller redirecting me when I'm trying to test it?
My controller:
class MyController < ApplicationController
before_filter :authenticate_user!, only: [:index]
def index
#example = "Just an example"
end
end
Stub user authentication as advised here in the Devise Wiki.
I am trying to write a RSpec before filter to log a user in. I have a products controller. In order to view products, a user must be logged in. I added a login method to spec/support/utilities like so:
def login(user)
post login_path, email: user.email, password: "password"
end
Then I called the method in a before filter in my spec/controllers/products test:
before :each do
user = FactoryGirl.create(:user)
login(user)
end
When I run the test I get the following error:
The action '/login' could not be found for ProductsController
I have a route for /login and my user authentication is simple - just like Railscasts #250 Authentication from Scratch. What am I missing?
If this is a controller spec, then the problem is that Routes are not available when unit testing controllers. The point is to test in isolation, which means no routes
Login is calling the ProductsController, that does not have a login method. As other told you, I wouldn't call one controller when you are testing another. Therefore, I think you should login some other way. For example:
def login(user)
session[:user_id] = user.id
end
How do I post to a different controller than the one the test script is currently pointing at?
Example:
in user_controller_spec.rb
it "should just post to users" do
post :create, #params # this goes to the users controller
end
I want to do something like:
it "should post to user and people to do some integration testing" do
post :create, #params # this goes to the users controller still
post 'people', :create, #params # this goes to the people controller
end
ps: i don't want to setup cucumber
Controller specs are wrappers for Rails functional tests, which don't support multiple requests or controllers. What you want is an RSpec request spec (rails 3) or an integration spec (rails 2). These wrap Rails integration tests, which does support multiple requests with multiple controllers (multiple sessions, even), but they work a bit differently from controller specs. You have to use the full path (so get new_thing_path), and you can't stub anything on the controller (because there is no controller before you make a request).
See http://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec and http://api.rubyonrails.org/classes/ActionDispatch/IntegrationTest.html for more info.
There is a way if you assigning the value of #controller before call test method. Example
def setup
#controller = UserController.New
do user stuff
#controller = ThisController.New
do test intented for this controller
end
Based on other answer, but more safe.
Store current controller instance and create a new with the required controller. Finally, replace new controller instance with the old stored instance.
def setup
old_controller = #controller
#controller = UserController.new
# do user stuff
#controller = old_controller
end