Rspec测试用于检查唯一性

时间:2012-10-02 01:47:58

标签: ruby-on-rails ruby ruby-on-rails-3 rspec

这是检查电子邮件唯一性的rspec测试(来自http://ruby.railstutorial.org/chapters/modeling-users.html#code-validates_uniqueness_of_email_test

require 'spec_helper'

describe User do

  before do
    @user = User.new(name: "Example User", email: "user@example.com")
  end
  .
  .
  .
  describe "when email address is already taken" do
    before do
      user_with_same_email = @user.dup
      user_with_same_email.save
    end

    it { should_not be_valid }
  end
end

正如作者所说,我添加了

class User < ActiveRecord::Base
  .
  .
  .
  validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
                    uniqueness: true
end

到我的用户模型并且测试通过。

但@user还没有保存到数据库中(我无法在任何地方找到@ user.save语句代码。)因此,user_with_same_email已经是唯一的,因为没有其他用户使用数据库中的同一封电子邮件。那它是如何工作的?

我在控制台中创建了类似的东西。 user_with_same_email.valid?返回false(错误&#34;已经采取&#34;),但user_with_same_email.save仍然有效。为什么呢?

2 个答案:

答案 0 :(得分:2)

以下是be_valid匹配器的source code

match do |actual|
  actual.valid?
end

如您所见,匹配器实际上并不保存记录,只是在实例上调用方法valid?valid?检查验证是否通过,如果没有,则在实例上设置错误消息。

在上面的案例中,您首先(成功)使用相同的电子邮件(user_with_same_email)保存用户,这是有效的,因为该电子邮件的用户实际上还没有已保存。然后,您正在检查具有相同电子邮件的另一个用户实例(@user)上的验证错误,即使您实际上没有保存重复记录,这显然也会失败。

关于您在控制台中获得的内容,问题可能是save即使失败也不会返回错误。请尝试使用save!

答案 1 :(得分:2)

您可以使用shoulda-matchers gem。

# spec/models/user_spec.rb
require 'spec_helper'

describe User, 'validations' do
  it { should validate_uniqueness_of(:email) }
  it { should validate_presence_of(:email) }
  it { should validate_format_of(:email).with_message(VALID_EMAIL_REGEX) }
end

对最后一个不肯定,但它看起来应该有效。

如果您正在使用许可,则可以使用内置的email_validator功能PR here

# app/models/user.rb
validates :email, presence: true, email: true