测试在Rails4命名范围的最佳方法(Best way to test named scopes i

2019-10-28 16:31发布

如从滑轨3.2迁移到导轨4的一部分,所有的命名范围需要一个PROC块。 在这里阅读更多: http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#active-record

我错过了在我的模型,最终咬我在我的生产迁移后的一个更新的范围。 所以我想弄清楚如何测试这个问题,我发现了一些奇怪的行为。

在某些情况下,范围似乎没有PROC在其他情况下正常工作,但不是。

# models/offer.rb
class Offer < ActiveRecord::Base

  scope :roster, where(:on_roster => true)
  scope :commit, where("status_id > 5")

end

如果我使用的每个作用域选项上轨控制台独立的来电,查询是否正确建立和结果回来的人会用Rails 3.2预料:

$ rails c
2.0.0-p247 :001 > Offer.roster.all.size
  Offer Load (1.6ms)  SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't'
=> 1
2.0.0-p247 :002 > Offer.commit.all.size
  Offer Load (1.6ms)  SELECT "offers".* FROM "offers" WHERE (status_id > 5)
=> 3

但是,如果我链上的两个范围在轨控制台呼叫起来,只能从链中最后一个范围的限制包括在每个查询:

2.0.0-p247 :003 > Offer.roster.commit.all.size
  Offer Load (1.4ms)  SELECT "offers".* FROM "offers" WHERE (status_id > 5)
 => 3
2.0.0-p247 :004 > Offer.commit.roster.all.size
  Offer Load (0.7ms)  SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't'
 => 1 

现在,如果我修改我的模型,一个进程添加到第二个命名范围,就像这样:

class Offer < ActiveRecord::Base

  scope :roster, where(:on_roster => true)
  scope :commit, -> { where("status_id > 5") }

end

如果指定的范围与定义的PROC是在链的末端,将建立与两个约束集的查询。 然而,如果没有定义的PROC命名范围是在链的末端,生成的查询是建立不与限定的PROC范围的限制。

$ rails c
2.0.0-p247 :003 > Offer.roster.commit.all.size
  Offer Load (1.4ms)  SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' AND (status_id > 5)
 => 0 
2.0.0-p247 :004 > Offer.commit.roster.all.size
  Offer Load (0.7ms)  SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't'
 => 1 

所以,第一个结果是正确的,并加载两个范围,但第二个不正确的,只加载最后一个范围。 然后,如果更改范围使用特效,就像这样:

# models/offer.rb
class Offer < ActiveRecord::Base

  scope :roster, -> { where(:on_roster => true) }
  scope :commit, -> { where("status_id > 5") }

end

你终于得到了预期的行为:

$ rails c
2.0.0-p247 :002 > Offer.roster.commit.all.size
  Offer Load (1.3ms)  SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' AND (status_id > 5)
 => 0
2.0.0-p247 :001 > Offer.commit.roster.all.size
  Offer Load (1.7ms)  SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' AND (status_id > 5)
 => 0 

一个说明这一点, reload! 在轨道控制台 ,您已经更新并保存你的模型后, 将不会更新范围的行为 。 你必须结束你的Rails控制台会话,并开始一个新来获取PROC与非PROC正确回暖。

我的问题是如何进行测试,以确保所有我的范围的预期行为? 我想测试他们是否有一个进程或lambda块看起来很凌乱每次链接范围在一起。 然而,简单的测试,我设置的范围,告诉我,我的所有范围都经过,并给假阳性结果。

有没有一种简单的方法通过Rspec的测试与Rails4命名范围是否位于一个进程或lambda块中?

Answer 1:

范围是用于定义类的方法,所以通过看它是完全不可能的代码知道你的内容是否已是一个进程/λ或不仅语法糖。

我唯一能想到的解决方案是使用RR和代理所述范围的方法。 这样,你可以抛出一个异常,如果身体不响应调用。 在您的测试,你比预期引发任何异常。 但我怀疑这是去工作,因为一旦你设置类已加载的代理,因此,范围方法被调用。

我想,而不是通过测试执行PROC使用,覆盖scope方法不允许非特效/ -lambdas在所有是一个更好的主意。

供参考: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/scoping/named.rb



文章来源: Best way to test named scopes in Rails4