如何使用 Shoulda 测试引用类属性的named_scope?

发布于 2024-07-12 10:13:47 字数 1512 浏览 7 评论 0 原文

我有以下 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

并且我正在尝试使用 named_scope :current_user “Shoulda">Shoulda 但以下不起作用。

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 添加到 setup 块中。

这是我测试这个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< 来测试它/a>?

I have the following ActiveRecord classes:

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

and I'm trying to test the named_scope :current_user using Shoulda but the following does not work.

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

The reason it doesn't work is because the call to User.current_user in the should_have_named_scope method is being evaluated when the class is being defined and I'm change the value of current_user afterwards in the setup block when running the test.

Here is what I did come up with to test this 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

So how would you test this using Shoulda?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

安穩 2024-07-19 10:13:47

我认为你处理这个问题的方式是错误的。 首先,为什么需要使用命名范围? 这不行吗?

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 ,它返回当前用户的 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.当前用户&& User.current_user.id 将返回一个布尔值,而不是您想要的整数。 编辑 我是个白痴。

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

I think you are going about this the wrong way. Firstly, why do you need to use a named scope? Wont this just do?

class BatchRecord < ActiveRecord::Base
  belongs_to :user

  def current_user
    self.user.class.current_user
  end
end

In which case it would be trivial to test. BUT! WTF are you defining current_user as a class attribute? Now that Rails 2.2 is "threadsafe" what would happen if you were running your app in two seperate threads? One user would login, setting the current_user for ALL User instances. Now another user with admin privileges logs in and current_user is switched to their instance. When the first user goes to the next page he/she will have access to the other persons account with their admin privileges! Shock! Horror!

What I reccomend doing in this case is to either making a new controller method current_user which returns the current user's User instance. You can also go one step further and create a wrapper model like:

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

Oh, and by the way, now I look at your question again perhaps one of the reasons it isn't working is that the line User.current_user && User.current_user.id will return a boolean, rather than the Integer you want it to. EDIT I'm an idiot.

Named scope is really the absolutely wrong way of doing this. Named scope is meant to return collections, rather than individual records (which is another reason this fails). It is also making an unnecessary call the the DB resulting in a query that you don't need.

再见回来 2024-07-19 10:13:47

我刚刚意识到答案就在盯着我。 我应该在关联的另一端(current_user.batch_records)工作。 然后我简单地在 User 模型上测试 named_scope ,一切都很好。

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

I just realized the answer is staring right at me. I should be working from the other side of the association which would be current_user.batch_records. Then I simply test the named_scope on the User model and everything is fine.

@Chris Lloyd - Regarding the thread safety issue, the current_user attribute is being set by a before_filter in my ApplicationController, so it is modified per request. I understand that there is still the potential for disaster if I chose to run in a multi-threaded environment (which is currently not the case). That solution I suppose would be another topic entirely.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文