Как заглушить метод ApplicationController в спецификации запроса
Мне нужно заглушить ответ метода current_user
в спецификации запроса Rspec/capybara. Метод определен в ApplicationController
и использует helper_method. Метод должен просто вернуть идентификатор пользователя. В рамках теста я хотел бы, чтобы этот метод возвращал один и тот же идентификатор пользователя каждый раз.
В качестве альтернативы я мог бы исправить свою проблему, установив session[:user_id]
в spec (что возвращает current_user
)... но это тоже не работает.
Возможны ли какие-либо из этих вариантов?
Edit:
Вот что я получил (он не работает, он просто запускает обычный метод current_user).
require 'spec_helper'
describe "Login" do
before(:each) do
ApplicationController.stub(:current_user).and_return(User.first)
end
it "logs in" do
visit '/'
page.should have_content("Hey there user!")
end
end
Также не работает:
require 'spec_helper'
describe "Login" do
before(:each) do
@mock_controller = mock("ApplicationController")
@mock_controller.stub(:current_user).and_return(User.first)
end
it "logs in" do
visit '/'
page.should have_content("Hey there user!")
end
end
Ответы
Ответ 1
skalee, похоже, дал правильный ответ в комментарии.
Если метод, который вы пытаетесь заглушить, является методом экземпляра (скорее всего), а не методом класса, то вам нужно использовать:
ApplicationController.any_instance.stub(:current_user)
Ответ 2
Вот несколько примеров базовой формы.
controller.stub(:action_name).and_raise([some error])
controller.stub(:action_name).and_return([some value])
В вашем конкретном случае я считаю, что правильная форма:
controller.stub(:current_user).and_return([your user object/id])
Вот полный рабочий пример проекта, над которым я работаю:
describe PortalsController do
it "if an ActionController::InvalidAuthenticityToken is raised the user should be redirected to login" do
controller.stub(:index).and_raise(ActionController::InvalidAuthenticityToken)
get :index
flash[:notice].should eql("Your session has expired.")
response.should redirect_to(portals_path)
end
end
Чтобы объяснить мой полный пример, в основном это означает, что при возникновении ошибки ActionController::InvalidAuthenticityToken
в любом месте приложения появляется сообщение со вспышкой, и пользователь перенаправляется на действие portals_controller#index
. Вы можете использовать эти формы для вывода и возврата определенных значений, проверки экземпляра заданной ошибки и т.д. Существует несколько доступных методов .stub(:action_name).and_[do_something_interesting]()
.
Обновить (после добавления кода): за мой комментарий измените свой код, чтобы он читал:
require 'spec_helper'
describe "Login" do
before(:each) do
@mock_controller = mock("ApplicationController")
@mock_controller.stub(:current_user).and_return(User.first)
end
it "logs in" do
visit '/'
page.should have_content("Hey there user!")
end
end
Ответ 3
Это работает для меня и дает мне переменную @current_user
для использования в тестах.
У меня есть помощник, который выглядит так:
def bypass_authentication
current_user = FactoryGirl.create(:user)
ApplicationController.send(:alias_method, :old_current_user, :current_user)
ApplicationController.send(:define_method, :current_user) do
current_user
end
@current_user = current_user
end
def restore_authentication
ApplicationController.send(:alias_method, :current_user, :old_current_user)
end
И затем в моих запросах спецификации я вызываю:
before(:each){bypass_authentication}
after(:each){restore_authentication}
Ответ 4
Для тех, кому, возможно, понадобится заглушить метод контроллера приложения, который устанавливает ivar (и был заглушен бесконечным wanking о том, почему вы не должны этого делать) здесь, способ, который работает, с ароматом Rspec около октября 2013 года.
before(:each) do
campaign = Campaign.create!
ApplicationController.any_instance.stub(:load_campaign_singleton)
controller.instance_eval{@campaign = campaign}
@campaign = campaign
end
он блокирует метод, чтобы ничего не делать, и устанавливает ivar на экземпляр контроллера rspec и делает его доступным для теста как @campaign.
Ответ 5
Ни один из предоставленных ответов не работал у меня. Как и в исходном посте @matt-fordam, у меня есть спецификация запроса, а не спецификация контроллера. Тест просто отображает представление без запуска контроллера.
Я решил это, наложив метод на представление, как описано в этом другом сообщении SO
view.stub(:current_user).and_return(etc)