首先,我应该提一下,我对Rails很新,这是我的第一个"认真的"项目,所以我很抱歉这是一个简单的问题,但我无法找到答案。
我在我的项目中使用TDD并使用RSpec编写模型测试,使用FactoryGirl创建模型,使用Faker创建模型的虚拟数据。在我添加测试以确保没有两个用户拥有相同的电子邮件地址之前,一切都进展顺利。在我的User
模型中,我对其进行了验证:
# /app/models/user.rb
validates :email, :password_reset_code, :auth_token, uniqueness: true
我的工厂使用Faker创建用户模型,如下所示:
# /spec/factories/users.rb
FactoryGirl.define do
factory :user do
email { Faker::Internet.email }
password { Faker::Internet.password }
password_reset_code { Faker::Lorem.word }
auth_token { Faker::Lorem.word }
end
end
我的user_spec.rb
测试如下:
# /spec/models/user_spec.rb
it "is invalid with a duplicate email" do
user = FactoryGirl.create(:user)
FactoryGirl.create(:user, email: user.email).should_not be_valid
end
在这里,我使用FactoryFirl创建一个新模型,使用Faker的虚拟值,将其保存到数据库,然后使用与第一个相同的电子邮件创建另一个模型。由于should_not be_valid
部分,我希望RSpec告诉我这个测试通过了。但是,当我运行测试时,我得到了这个输出:
Failures:
1) User is invalid with a duplicate email
Failure/Error: FactoryGirl.create(:user, email: user.email).should_not be_valid
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/models/user_spec.rb:19:in `block (2 levels) in <top (required)>'
所以似乎模型验证引发了一个错误,RSpec没有抓住并使用它来通过测试?我已经设法通过将测试更改为:
来解决它it "is invalid with a duplicate email" do
begin
user = FactoryGirl.create(:user)
FactoryGirl.create(:user, email: user.email).should_not be_valid
rescue
false
end
end
似乎可以工作,不过我觉得这不是最好的方法。
编写此测试的正确方法是什么?
答案 0 :(得分:1)
我也遇到了这个问题。您遇到的错误是由于create()方法实际上持久化了模型,然后在DB层(以及持久层)抛出ActiveRecord :: RecordInvalid。如果要断言模型是否有效,则应对第二个对象使用build()方法,然后询问它是否有效。您可以在此post中阅读。
此外,如果您只是尝试在模型上测试各种验证,而不是我写了一些快速而肮脏的gem,您可以使用它来断言一些更基本的模型验证。您可以查看here。
希望有所帮助。
答案 1 :(得分:0)
我会选择:
# /spec/models/user_spec.rb
describe 'validations' do
context 'with a duplicate email' do
let(:other_user) { FactoryGirl.create(:user) }
let(:attributes) { FactoryGirl.attributes_for(:user) }
subject(:user) { User.new(attributes.merge(email: user.email)) }
it 'is not valid' do
expect(user).to_not be_valid
end
end
end