我怎么能指定before_filters?
我想用rspec指定我的控制器before_filter。 我想为它使用ActionController :: Testing :: ClassMethods#before_filters。
我在导轨c中得到了这些结果:
2.0.0p353 :006 > ActionController::Base.singleton_class.send :include, ActionController::Testing::ClassMethods 2.0.0p353 :003 > EquipmentController.before_filters
=> [:process_action,:process_action]
但实际上这是我行动的filter:
class EquipmentController < ApplicationController before_filter :authenticate_user!
有任何想法吗?
这就是我在项目中所做的:
# spec/support/matchers/have_filters.rb RSpec::Matchers.define :have_filters do |kind, *names| match do |controller| filters = controller._process_action_callbacks.select{ |f| f.kind == kind }.map(&:filter) names.all?{ |name| filters.include?(name) } end end # spec/support/controller_macros.rb module ControllerMacros def has_before_filters *names expect(controller).to have_filters(:before, *names) end end # spec/spec_helper.rb RSpec.configure do |config| config.include ControllerMacros, type: :controller end
然后你可以在控制器规格中使用它,例如:
# spec/controllers/application_controller_spec.rb require 'spec_helper' describe ApplicationController do describe 'class' do it { has_before_filters(:authenticate_user) } end end
我想出了一种基于ActionController :: Testing :: ClassMethods#before_filter的源代码的方法
这将是我的规格:
describe EquipmentController do context 'authentication' do specify{ expect(EquipmentController).to filter(:before, with: :authenticate_user!, only: :index)} end ...
这是我在spec / support / matchers / filter.rb中的匹配器
RSpec::Matchers.define :filter do |kind, filter| match do |controller| extra = -> (x) {true} if filter[:except].present? extra = -> (x) { x.options[:unless].include?( "action_name == '#{filter[:except]}'") } elsif filter[:only].present? extra = -> (x) { x.options[:if].include?( "action_name == '#{filter[:only]}'") } end controller._process_action_callbacks.find{|x|x.kind == kind && x.filter == filter[:with] && extra.call(x)} end end
嗯,我不清楚你想要测试什么,确切地说。 听起来你正在测试它的存在
before_filter :authenticate_user!
但这只有在您知道:authenticate_user!
时才有用:authenticate_user!
表现得像你想要的那样。 所以我建议双管齐下的测试攻击 –
- 测试#authenticate_user! 根据您的规格行事
- 编写规范以确保在用户登录和注销时使用before_filter保护的方法具有正确的行为。
习惯上, before_filter
方法被声明为私有 ,因此您的规范可能类似于:
describe ApplicationController do describe 'GET /my_account' do # a method to which the before_filter applies subject { get :my_account } context 'with a logged-out session' do it 'redirects to the homepage' do response.should redirect_to root_url end end context 'with a logged-in session' do # if you use FactoryGirl and have a spec helper method log_in() to set up the session before { log_in(FactoryGirl.create :user) } it { should render_template('my_account') } # etc... end end describe 'private #authenticate_user!' do subject { ApplicationController.send(:authenticate_user!) } it 'calls the authentication logic' do Authentication.expects(:attempt_login) # or whatever to verify the internals subject end end end
通过单独测试,您可以validation是否保持了所需的行为,无论以下实现如何:authenticate_user!
或其他登录内部。 并且,您可以在不过分依赖Rails内部的情况下实现这一目标!
如果这有任何意义,请告诉我。 我对StackOverflow比较新,所以反馈非常感谢!
这是你可以做的:
-
是
authenticate_user!
你自己编写的方法,还是像Rails或Devise这样的gem附带的方法? 如果您没有编写该方法,则无需为其编写测试。 只测试你自己编写的代码。 gem的作者已经为他们的代码编写了测试。 -
如果你想测试方法
authenticate_user!
在控制器中调用,您可以在规范中执行controller.should_receive(:authenticate_user!)
来检查它是否被调用。 -
您还可以通过编写如下规范来检查EquipmentController是否调用before_filter:
EquipmentController.should_receive(:before_filter).with(:authenticate_user!)
shoulda- use_after_action
gem为您提供use_after_action
, use_around_action
和use_before_action
,它们是简单的回调测试。 无需编写自定义匹配器。