【问题标题】:RSpec test for not allowing two users with the same email addressRSpec 测试不允许两个用户使用相同的电子邮件地址
【发布时间】:2014-11-24 09:39:05
【问题描述】:

首先我应该提一下,我对 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

在这里,我使用 FactoryGirl 使用来自 Faker 的虚拟值创建一个新模型,将其保存到数据库中,然后使用与第一个相同的电子邮件创建另一个模型。我希望 RSpec 告诉我这个测试通过了,因为 should_not be_valid 部分。但是当我运行测试时,我得到了这个输出:

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

似乎可行,但我觉得这不是最好的方法。

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

【问题讨论】:

标签: ruby-on-rails ruby testing rspec


【解决方案1】:

我也遇到了这个问题。您遇到的错误是由于 create() 方法实际上保留了模型,然后在 DB 层(嗯,持久层)抛出 ActiveRecord::RecordInvalid。如果你想断言一个模型是否有效,你应该为你的第二个对象使用 build() 方法,然后询问它是否有效。你可以在这个post阅读它。

此外,如果您只是想测试模型上的各种验证,我写了一个快速而肮脏的 gem,您可以使用它来断言一些更基本的模型验证。您可以查看here

希望对您有所帮助。

【讨论】:

  • 仅供参考,如果您要使用我链接到的 gem,可以通过以下代码行测试唯一性:Record.field_uniqueness(FactoryGirl.create(:user), :email)
  • 谢谢,将第二个 create 更改为 build,现在运行良好。那个宝石看起来很有用,我去看看:)
【解决方案2】:

我会选择:

# /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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 2018-11-16
    • 1970-01-01
    • 2015-01-23
    • 2017-06-14
    • 2016-11-12
    相关资源
    最近更新 更多