我看到非常奇怪的行为,其中是否运行过滤器似乎取决于它是否设置为在第一个规范中运行以使用该控制器。
所以我把它减少到一个最小的控制器:
class WtfController < ActionController::Base
before_filter :raise_error
def index
render nothing: true, status: 200
end
private
def raise_error
raise OMGError
end
end
(OMGError只是StandardError的子类)
一个测试用例:
describe 'wtfspec' do
it 'with filter' do
expect do
controller = set_up_controller
controller.process(:index)
end.to raise_error
end
it 'without filter' do
expect do
controller = set_up_controller
controller.class.skip_filter :raise_error
controller.process(:index)
end.not_to raise_error
end
end
def set_up_controller
controller = WtfController.new
controller.request = ActionController::TestRequest.new
controller.response = ActionController::TestResponse.new
controller
end
在第二次测试中应该跳过过滤器,但它不是。
如果未运行第一个expect块,则第二个测试通过。只有当第二次失败时才运行它。同样,如果我在第一次测试中skip_filter
并使用before_filter
为第二次测试读取它,那么第二次测试就无法运行过滤器。
这就是事情 - 如果我在controller.class._process_action_callbacks.map(&:filters)
行之前的规范(第二次测试)中检查WtfController上设置的过滤器列表(使用controller.process
),那么它确实已成功删除,skip_filter
行正常工作。但如果我在控制器中检查它(在raise_error
中),它似乎已经以某种方式被读取了!
注意&#39; readded&#39;,而不是&#39;:实际运行的raise_error
回调的object_id与原始回调(运行之前的那个)不同skip_filter
)。但是过滤器数组的object_id(实际上是ActiveSupport::Callbacks::CallbackChain
)与控制器一样保持不变。
(编辑:结果是所有的回调对象都有不同的object_ids,而不仅仅是被移除的。神秘加深......)
无论两个测试中的每一个都是新的控制器对象还是重用相同的控制器对象(因为过滤器是WtfController类对象的属性),行为是相同的,不是实例)。
我花了一天时间调试这个并且完全神秘化了。有任何见解赞赏。 Rails版本是3.2.21。谢谢:))
答案 0 :(得分:0)
在测试不同的rails版本后,这种行为在4.0中不会发生。因此可能是导轨中的一个错误,现在已经修复了。可能与activesupport中的this commit相关。