【问题标题】:How to test a named_scope that references a class attribute with Shoulda?如何使用 Shoulda 测试引用类属性的 named_scope?
【发布时间】:2009-01-21 23:36:12
【问题描述】:

我有以下 ActiveRecord 类:

class User < ActiveRecord::Base
  cattr_accessor :current_user
  has_many :batch_records
end

class BatchRecord < ActiveRecord::Base
  belongs_to :user

  named_scope :current_user, lambda {
    { :conditions => { :user_id => User.current_user && User.current_user.id } }
  }
end

我正在尝试使用Shoulda 测试named_scope :current_user,但以下不起作用。

class BatchRecordTest < ActiveSupport::TestCase
  setup do
    User.current_user = Factory(:user)
  end

  should_have_named_scope :current_user,
                          :conditions => { :assigned_to_id => User.current_user }
end

它不起作用的原因是因为在定义类时正在评估should_have_named_scope 方法中对User.current_user 的调用,然后我将在current_user 中更改current_user 的值@ 987654329@运行测试时阻塞。

这是我为测试这个 named_scope 所做的:

class BatchRecordTest < ActiveSupport::TestCase
  context "with User.current_user set" do
    setup do
      mock_user = flexmock('user', :id => 1)
      flexmock(User).should_receive(:current_user).and_return(mock_user)
    end

    should_have_named_scope :current_user,
                            :conditions => { :assigned_to_id => 1 }
  end
end

那么您将如何使用 Shoulda 进行测试?

【问题讨论】:

    标签: ruby-on-rails ruby unit-testing shoulda


    【解决方案1】:

    我认为你的做法是错误的。首先,为什么需要使用命名范围?就这样不行吗?

    class BatchRecord < ActiveRecord::Base
      belongs_to :user
    
      def current_user
        self.user.class.current_user
      end
    end
    

    在这种情况下,测试将是微不足道的。但! WTF 您是否将current_user 定义为类属性?现在 Rails 2.2 是“线程安全的”,如果你在两个单独的线程中运行你的应用程序会发生什么?一位用户将登录,为所有User 实例设置current_user。现在另一个具有管理员权限的用户登录并current_user 切换到他们的实例。当第一个用户进入下一页时,他/她将可以使用其他人的管理员权限访问帐户!震惊!恐怖!

    在这种情况下我建议做的是创建一个新的控制器方法current_user,它返回当前用户的用户实例。您还可以更进一步,创建一个包装器模型,例如:

    class CurrentUser
    
      attr_reader :user, :session
    
      def initialize(user, session)
        @user, @session = user, session
      end
    
      def authenticated?
        ...
      end
    
      def method_missing(*args)
        user.send(*args) if authenticated?
      end
    
    end
    

    哦,顺便说一句,现在我再次查看您的问题,也许它不起作用的原因之一是 User.current_user &amp;&amp; User.current_user.id 行将返回布尔值,而不是您想要的整数. 编辑我是个白痴。

    命名范围确实是绝对错误的做法。命名范围旨在返回集合,而不是单个记录(这是失败的另一个原因)。它还会对数据库进行不必要的调用,从而导致您不需要的查询。

    【讨论】:

    • Ruby 逻辑运算符(&&、||)不能按照您建议的方式工作。他们返回评估的最后一个参数。因此,如果 User.current_user 或 User.current_user.id 是布尔值,那么 current_user 代码只会返回一个布尔值——我认为情况并非如此。
    • 哎呀,你是对的!清晨喝酒对我的 Ruby 技能没有帮助。
    【解决方案2】:

    我刚刚意识到答案正盯着我看。我应该在协会的另一端工作,即current_user.batch_records。然后我简单地在User 模型上测试named_scope,一切都很好。

    @Chris Lloyd - 关于线程安全问题,current_user 属性是由我的before_filter 中的ApplicationController 设置的,因此它会根据请求进行修改。我知道如果我选择在多线程环境中运行(目前不是这种情况),仍然有可能发生灾难。我认为该解决方案将完全是另一个主题。

    【讨论】:

    • 我以前不得不不断地绕过 current_user,我想在读完之后,我只需要忍受它。感谢您的 cmets。
    猜你喜欢
    • 2011-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多