双重的.as_null_object导致Rspec挂起?

时间:2012-01-17 14:54:41

标签: ruby-on-rails ruby-on-rails-3 rspec sorcery

我不太清楚如何解释这一点。

我有一个运行RSpec 2.8.1的现有Rails 3.1.3应用程序,带有284个测试的测试套件。他们会一遍又一遍地愉快地执行。

我今天为用户更新了他们的设置添加了一项新测试 -

require 'spec_helper'

describe UserSettingsController do

  describe 'PUT "update"' do

    let!(:user) { Fabricate :user }

    it 'updates the User with the correct attributes' do
      proxy = double('proxy')   #.as_null_object
      controller.should_receive(:current_user).any_number_of_times { proxy }

      attributes = Fabricate(:user_settings).stringify_keys
      proxy.should_receive(:update_attributes).with(attributes, :as => :updater) { true }

      login_user(user)
      put :update, :user => attributes
    end

  end

end

最初这个测试失败了,因为我的application_controller.rb中有一个before_filter,它也引用了current_user(这会在mock上产生意外的消息),所以我想把mock作为一个空对象(参见上面注释掉的区域)。

当我这样做时...整个测试套件在完成测试后(但在继续下一个测试之前)就像在无限循环中一样挂起。

以前有人见过这样的事吗?我是否正确使用.as_null_object?

编辑以澄清一些事情,login_user是Sorcery提供的用于在测试中进行身份验证的帮助程序,:user_settings制造商只是使用时区制作哈希在它。

1 个答案:

答案 0 :(得分:1)

除非你:user_settings工厂是自我指涉的,否则我会考虑做两件事。第一:

describe UserSettingsController do

  describe 'PUT "update"' do
    let(:proxy) { double('proxy').as_null_object }
    let(:user) { Fabricate :user }

    before(:each) do
      login_user(user)
    end

    it 'updates the User with the correct attributes' do
      controller.should_receive(:current_user).any_number_of_times { proxy }

      attributes = Fabricate(:user_settings).stringify_keys
      proxy.should_receive(:update_attributes).with(attributes, :as => :updater) { true }

      put :update, :user => attributes
    end

  end

end

如果这样失败,你就会知道问题出在魔法内部。 (你永远不会在控制台中看到示例摘要字符串输出。)请注意,我保留了#as_null_object调用:sorcery会刺激被模拟的用户获取信息,主要是填充哈希值。如果您有兴趣,请开始阅读here。如果 无法帮助查明问题,请考虑完全删除login_user。像这样:

describe UserSettingsController do

  describe 'PUT "update"' do
    let(:proxy) { double('proxy') }
    let(:user) { Fabricate :user }

    it 'updates the User with the correct attributes' do
      controller.should_receive(:current_user).any_number_of_times { proxy }

      attributes = Fabricate(:user_settings).stringify_keys
      proxy.should_receive(:update_attributes).with(attributes, :as => :updater) { true }

      put :update, :user => attributes
    end

  end

end

你将current_user存根到控制器定义,我认为意味着你会超过你的before_filter auth钩子,将current_user定义为proxy }。如果在所有调用中都发生了一些愚蠢的事情,那么你至少会减少一些调用。

我还在猜测 - 我没有构建一个示例应用程序。祝你好运。