Rspec和FactoryGirl唯一性失败

时间:2013-12-10 16:59:33

标签: ruby ruby-on-rails-4 factory-bot rspec-rails

我将简要介绍代码示例,因为我的所有测试都通过了以下测试。我通过改变一些东西来通过它,但我不确定为什么版本1失败并且版本2工作。

我的模特:

# app/models/person.rb
class Person
validates :contact_number, uniqueness: true
end

模型规范

# spec/models/person_spec.rb
require 'spec_helper'
describe Person do
  it 'is a valid factory' do
    create(:person).should be_valid # passes
  end

  it 'has a unique phone number' do
    create(:person)
    build(:person).should_not be_valid # fails
  end

  it 'also has a unique phone number' do
    person1 = create(:person)
    person2 = person1.dup
    person2.should_not be_valid # passes
  end
end

据我所知,两个唯一性测试应该做同样的事情,但是一个通过,一个失败。

如果重要,我正在使用mongoid,虽然我不认为这会产生任何影响。我也没有对嵌套上下文做任何事情或在我的测试中描述,所以我认为范围是正确的。任何见解都表示赞赏。

更新1:我在工厂意识到我正在添加initialize_with这样的块:

initialize_with { Person.find_or_create_by(contact_number: contact_number) }

我意识到这可能是验证失败的原因 - 我只是让同一个人回来了。但是,注释掉该行会出现以下错误:

  

Mongoid ::错误::验证:   问题:     验证人员失败。   摘要:     发现以下错误:已接受联系号码   解析度:     尝试使用有效数据保留文档或删除验证。

我认为理论上是好的,因为它不会让我用相同的联系号码保存第二个人,但我更希望我的测试通过。

3 个答案:

答案 0 :(得分:1)

可能你的工厂工厂有一个contact_number序列,每个人都有不同的contact_number。

只是意识到构建(:person)没有验证。验证仅在create中进行。 我强烈建议您使用shoulda-matchers进行此类验证。

答案 1 :(得分:0)

您的数据库可能正在被清理(您的Gemfile中是否有数据库清理程序),或者您的测试没有按照您认为的顺序运行。 (检查:random中的spec_helper.rb

虽然上面关于使用shoulda-matchers的答案将帮助您更简洁地在RSpec中运行此特定测试,但您可能希望让您的独特电话号码测试能够完全独立运行而无需依赖其他规范已经执行了。你的第二个测试是一个模糊测试的例子(还有一点神秘访客http://robots.thoughtbot.com/mystery-guest),从测试代码中不清楚实际测试的是什么。您的电话号码参数在另一个文件(工厂)中定义,之前的数据设置正在文件中其他位置的另一个规范中运行。

您的第二次测试已经更好了,因为它更明确地显示您正在测试的内容,并且不依赖于已运行的其他规范。我实际上会这样写它以使其更明确:

it 'has a unique phone number' do
  person1 = create(:person, phone_number: '555-123-4567')
  person2 = create(:person, phone_number: '555-123-4567')

  # can use 'should' here instead
  expect(person2).not_to be_valid
end

如果您没有明确说明电话号码,那么即使您的代码仍然健全,如果您更改工厂,此测试可能会开始失败。此外,如果您有其他要验证唯一性的属性,即使缺少电话号码验证,您之前的测试也可能会通过。

答案 2 :(得分:0)

我明白了!一时兴起,我检查了测试数据库,注意到一个Person对象挥之不去。所以,它实际上不是 build(:person).should_not be_valid提出了Mongoid异常。这是之前在线上的创建调用。清除数据库并再次运行规范,但数据仍然存在。我仔细检查了我的spec_helper.rb文件,发现我没有在start上调用DatabaseCleaner。我更新的spec_helper.rb文件如下所示,现在一切正常:

# Clean up the database
require 'database_cleaner'

config.mock_with :rspec

config.before(:suite) do
  DatabaseCleaner.strategy = :truncation
  DatabaseCleaner.orm = "mongoid"
end

config.before(:each) do
  DatabaseCleaner.start
end

config.after(:each) do
  DatabaseCleaner.clean
end