【问题标题】:Why does this spec of my model's uniqueness validation fail when it should pass?为什么我的模型的唯一性验证规范在应该通过时却失败了?
【发布时间】:2016-01-16 17:39:25
【问题描述】:

我正在学习使用 RSpec 进行测试。我的测试无法正常工作。

我的模特:

class User < ActiveRecord::Base
  has_secure_password

  # Validation macros
  validates_presence_of :name, :email
  validates_uniqueness_of :email, case_sensitive: false
end

我的工厂:

FactoryGirl.define do
  factory :user do
    name "Joe Doe"
    email "joe@example.com"
    password_digest "super_secret_password"
  end
end

还有我的规格:

require 'rails_helper'

RSpec.describe User, type: :model do
  user = FactoryGirl.build(:user)

  it 'has a valid factory' do
    expect(FactoryGirl.build(:user)).to be_valid
  end

  it { is_expected.to respond_to(:name) }
  it { is_expected.to respond_to(:email) }
  it { is_expected.to respond_to(:password) }
  it { is_expected.to respond_to(:password_confirmation) }

  it { expect(user).to validate_presence_of(:name) }
  it { expect(user).to validate_presence_of(:email) }
  it { expect(user).to validate_presence_of(:password) }
  it { expect(user).to validate_uniqueness_of(:email).case_insensitive }
end

我预计这个测试会通过。但我得到了这个结果:

失败:

1) 用户应该验证 :email 是不区分大小写的唯一 失败/错误:它 { expect(user).to validate_uniqueness_of(:email).case_insensitive }

   User did not properly validate that :email is case-insensitively unique.
     The record you provided could not be created, as it failed with the
     following validation errors:

     * name: ["can't be blank"]
 # ./spec/models/user_spec.rb:18:in `block (2 levels) in <top (required)>'

在 0.34066 秒内完成(文件加载需要 1.56 秒)9 示例,1 次失败

失败的例子:

rspec ./spec/models/user_spec.rb:18 # 用户应该验证 :email 是不区分大小写的唯一性

我错过了什么?

更新

我认为这是一个错误:https://github.com/thoughtbot/shoulda-matchers/issues/830

【问题讨论】:

  • 您是否在测试之间清除数据库?
  • @CodeGnome,是的......我是
  • @CodeGnome 我尝试禁用清理数据库的脚本,但错误依旧

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


【解决方案1】:

您的变量目前只为所有测试设置一次

当你编写如下代码时:

RSpec.describe User, type: :model do
  user = FactoryGirl.build(:user)
end

每次运行新规范时,您都不会建立新用户。同样,使用#let 是错误的方法,因为it memoizes the variable 即使在测试之间也是如此。相反,您需要使用 RSpec before#each 块。例如:

describe User do
  before do
    @user = FactoryGirl.build :user
  end

  # some specs
end

如果您有将用户持久保存到数据库的测试,并且如果您在测试之间禁用了回滚或数据库清理,那么您定义的工厂(如当前编写的)肯定会无法通过唯一性验证。在这种情况下,您可能需要尝试:

  • User.delete_all 在您的测试中,或者在测试之间清理您的数据库。
  • 使用FactoryGirl sequencesFaker gem 确保用户属性实际上是唯一的。

【讨论】:

【解决方案2】:

USE let

RSpec.describe User, type: :model do
  let(:user) { FactoryGirl.build(:user) }

  # other what you need

【讨论】:

【解决方案3】:

这是因为您要声明 2 次 IMO!首先构建用户,然后在 expect() 中构建相同的用户。

只需使用您使用 factory-bot 构建的第一个用户,如下所示:

it 'has a valid factory' do
    expect(user).to be_valid
end

附言 最好使用 Faker gem 而不是像在 factory.rb 中那样使用硬编码实例

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多