Как заглушить метод ApplicationController в спецификации запроса - PullRequest
59 голосов
/ 16 сентября 2011

Мне нужно заглушить ответ метода current_user в спецификации запроса Rspec / capybara. Метод определен в ApplicationController и использует helper_method. Метод должен просто возвращать идентификатор пользователя. В рамках теста мне бы хотелось, чтобы этот метод каждый раз возвращал один и тот же идентификатор пользователя.

В качестве альтернативы, я мог бы решить мою проблему, установив session[:user_id] в спецификации (что возвращает 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

Ответы [ 6 ]

58 голосов
/ 30 августа 2012

Скали, кажется, дал правильный ответ в комментарии.

Если метод, который вы пытаетесь заглушить, является методом экземпляра (скорее всего), а не методом класса, тогда вам нужно использовать:

ApplicationController.any_instance.stub(:current_user)

14 голосов
/ 16 сентября 2011

Вот несколько примеров базовой формы.

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 голосов
/ 14 октября 2012

Это работает для меня и дает мне переменную @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}
2 голосов
/ 07 ноября 2013

Для всех, кому нужно заглушить метод контроллера приложения, который устанавливает ivar (и был заблокирован бесконечным блужданием о том, почему вы не должны этого делать), вот способ, который работает, со вкусом 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.

1 голос
/ 19 июня 2018

Для Rspec 3+ новый API:

Для проверки контроллера, красиво и коротко:

allow(controller).to receive(:current_user).and_return(@user)

Или для всех экземпляров ApplicationController:

allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(@user)
1 голос
/ 18 ноября 2013

Ни один из предоставленных ответов не работал для меня.Как и в оригинальном посте @ matt-fordam, у меня есть спецификация запроса, а не спецификация контроллера.Тест просто отображает представление без запуска контроллера.

Я решил эту проблему, поставив метку метода на представление, как описано в этом другом SO сообщении

view.stub(:current_user).and_return(etc)
...