【问题标题】:Railstutorial.org Validating unique emailRailstutorial.org 验证唯一的电子邮件
【发布时间】:2012-01-04 05:46:28
【问题描述】:

Ruby on Rails 3 教程 的 6.2.4 节中,Michael Hartl 描述了关于检查电子邮件地址唯一性的警告:如果两个相同的请求及时接近,则请求 A 可以通过验证,然后B 通过验证,然后 A 被保存,然后 B 被保存,你得到两个具有相同值的记录。每个在检查时都是有效的。

我的问题是关于解决方案的不是(在数据库上设置唯一约束,因此 B 的保存将不起作用)。这是关于编写测试以证明解决方案有效。我尝试自己编写,但我想出的任何东西都只是模仿了常规的、简单的唯一性测试。

对于 rspec 来说是全新的,我天真的方法是只编写场景:

it 'should reject duplicate email addresses with caveat' do
  A = User.new( @attr ) 
  A.should be_valid          # always valid

  B = User.new( @attr )
  B.should be_valid          # always valid, as expected

  A.save.should == true      # save always works fine

  B.save.should == false     # this is the problem case
  # B.should_not be_valid    # ...same results as "save.should"
end

但此测试在与常规唯一性测试完全相同的情况下通过/失败; B.save.should == false 在编写我的代码时通过,以便常规唯一性测试通过并在常规测试失败时失败。

所以我的问题是“我怎样才能编写一个 rspec 测试来验证我正在解决这个问题?”如果答案是“它很复杂”,我应该看看不同的 Rails 测试框架吗?

【问题讨论】:

  • 顺便说一句,这是一个很好的第一个问题。

标签: ruby-on-rails rspec rspec-rails railstutorial.org


【解决方案1】:

这很复杂。竞争条件之所以如此恶劣,正是因为它们难以重现。在内部,save 是这样的:

  1. 验证。
  2. 写入数据库。

因此,要重现计时问题,您需要将两个 save 调用安排为像这样重叠(伪 Rails):

a.validate    # first half of a.save
b.validate    # first half of b.save
a.write_to_db # second half of a.save
b.write_to_db # second half of b.save

但你不能打开save 方法并如此轻易地摆弄它的内部结构。

但是(这是一个很大的但是),you can skip the validations entirely

请注意,save 也可以在将 :validate => false 作为参数传递时跳过验证。应谨慎使用此技术。

所以如果你使用

b.save(:validate => false)

您应该只获得bsave 的“写入数据库”一半,并将您的数据发送到数据库而无需验证。这应该会触发数据库中的约束违规,我很确定这会引发ActiveRecord::StatementInvalid 异常,所以我认为您需要寻找异常,而不仅仅是来自save 的错误返回:

b.save(:validate => false).should raise_exception(ActiveRecord::StatementInvalid)

您也可以将其收紧以查找特定的异常消息。我没有任何方便的工具来测试此测试,因此请在 Rails 控制台中尝试并适当调整您的规范。

【讨论】:

  • 可爱。谢谢。我尝试了几次检查,因为...我实际上做错了唯一性,而且我的索引不是,实际上是唯一的。来自控制台的实际错误是ActiveRecord::RecordNotUnique: SQLite3::SQLException: column email is not unique: ...。最后,我需要lambda 来检查异常情况:lambda { B.save(:validate => false ) }.should raise_exception(ActiveRecord::RecordNotUnique)
  • @mcdave:很酷,测试应该会发现错误:)
猜你喜欢
  • 2021-08-22
  • 2014-05-23
  • 2020-03-12
  • 1970-01-01
  • 2015-03-24
  • 2014-06-08
  • 2016-08-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多