我将简要介绍代码示例,因为我的所有测试都通过了以下测试。我通过改变一些东西来通过它,但我不确定为什么版本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 ::错误::验证: 问题: 验证人员失败。 摘要: 发现以下错误:已接受联系号码 解析度: 尝试使用有效数据保留文档或删除验证。
我认为理论上是好的,因为它不会让我用相同的联系号码保存第二个人,但我更希望我的测试通过。
答案 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