RSpec测试不允许两个用户使用相同的电子邮件地址

时间:2014-09-29 21:36:29

标签: ruby-on-rails ruby testing rspec

首先,我应该提一下,我对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
似乎可以工作,不过我觉得这不是最好的方法。

编写此测试的正确方法是什么?

2 个答案:

答案 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