如何正确使用具有唯一性验证的shoulda匹配器?

时间:2017-06-27 01:09:15

标签: ruby-on-rails rspec

我正在尝试使用rspec和shoulda matchers作为我的新测试框架,我对如何通过should validate_uniqueness_of(:attribute)测试感到有些困惑。这是我的简单模型:

class Employee < ActiveRecord::Base
  validates :name, presence: true
  validates :title, presence: true
  validates :department, presence: true
  validates :avatar, presence: true 
  validates :email, presence: true, uniqueness: true
  validates :reports_to, presence: true
  mount_uploader :avatar, EmployeeAvatarUploader, on: :file_name
end

这是初步测试:

RSpec.describe Employee, type: :model do
  it { should validate_presence_of(:name) }
  it { should validate_presence_of(:title) }
  it { should validate_presence_of(:department) }
  it { should validate_presence_of(:avatar) }
  it { should validate_presence_of(:email) }
  it { should validate_uniqueness_of(:email) } 
  it { should validate_presence_of(:reports_to) }
end

此操作失败并显示下面粘贴的错误说明:

`1) Employee should validate uniqueness of email
 Failure/Error: should validate_uniqueness_of(:email)

 Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher::ExistingRecordInvalid:
   validate_uniqueness_of works by matching a new record against an
   existing record. If there is no existing record, it will create one
   using the record you provide.

   While doing this, the following error was raised:

     PG::NotNullViolation: ERROR:  null value in column "title" violates not-null constraint
     DETAIL:  Failing row contains (21, null, null, null, null, null, null, 2017-06-27 01:07:49.125445, 2017-06-27 01:07:49.125445, null, null).
     : INSERT INTO "employees" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"

   The best way to fix this is to provide the matcher with a record where
   any required attributes are filled in with valid values beforehand.`

所以我对文档的印象是我的测试应该按原样运行。从shoulda matcher文档中,我已经尝试过这个版本的测试:

RSpec.describe Employee, type: :model do
  it { should validate_presence_of(:name) }
  it { should validate_presence_of(:title) }
  it { should validate_presence_of(:department) }
  it { should validate_presence_of(:avatar) }
  it { should validate_presence_of(:email) }
  it 'should validate uniqueness of email' do
    email1 = FactoryGirl.create(:account, email: 'email@blackducksoftware.com')
    email2 = FactoryGirl.build(:account, email: 'email@blackducksoftware.com' )
    should validate_uniqueness_of(:email)
  end
  it { should validate_presence_of(:reports_to) }
end

这似乎也没有用。然后,我点击Rspec validates_uniqueness_of此链接

尝试了此测试的变体

但仍然没有运气。有人可以指导我进行这种验证的正确方法吗?

2 个答案:

答案 0 :(得分:1)

你应该能够这样称呼它:

describe "validations" do
  subject { Employee.new(title: "Here is the content") }
  it { should validate_uniqueness_of(:email) }
end

FactoryGirl

describe "validations" do
  subject { FactoryGirl.build(:employee) }
  it { should validate_uniqueness_of(:email) }
end

您的employees表的数据库级别约束需要title,因此您需要先创建一个有效的employee对象。

在您的第二个示例中,您似乎正在构建account而不是employee

请参阅此处的文档:docs

答案 1 :(得分:0)

describe Employee, type: :model do
  context 'validations' do
    it { should validate_uniqueness_of(:email) }
  end
end

在这里,主体是隐含的。构建了Employee的新实例(未创建)并验证了验证。