rails minitest让我疯狂PG :: UniqueViolation错误

时间:2018-05-24 05:00:32

标签: ruby-on-rails factory-bot minitest

有一半的时间我可以让我的测试运行。另一半他们因为唯一性违规而失败,这是我无法找到的来源。现在我在后半段。我的错误是:

ItemTest#test_valid_setup:
ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_blobs_on_user_id_and_item_id"
DETAIL:  Key (user_id, item_id)=(1, 1) already exists.
: INSERT INTO "blobs" ("user_id", "item_id", "amount", "active", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"
 test/models/item_test.rb:15:in `setup'

我有factories.rb

FactoryBot.define do
 factory :user, aliases: [:owner] do
  email "test@test.com"
  username "test"
 end

 factory :item do
  owner
  image { loads file etc... }
  price 100
  ...
 end

 factory :blob, aliases: [:wanted, :collateral] do
  user
  item
  amount 0
  active true
 end
end

我的item_test.rb

require 'test_helper'
require 'support/database_cleaner'

class ItemTest < Minitest::Test
 def setup
  DatabaseCleaner.start
  #create users
  @user1 = FactoryBot.create(:user, email: "a@pear.com", username: "barnyard")
  @user2 = FactoryBot.create(:user, email: "bo@ichi.com", username: "ponygrl")
  @user3 = FactoryBot.create(:user, email: "ho@ho.com", username: "hon")

  #create items
  @item1 = FactoryBot.create(:item, owner: @user1)
  @item2 = FactoryBot.create(:item, owner: @user2, price: 101)
  @item3 = FactoryBot.create(:item, owner: @user3, price: 102)

  #create blobs
  @blob1 = FactoryBot.create(:blob, user: @user1, item: @item1, amount: @item1.price, active: false)
  @blob2 = FactoryBot.create(:blob, user: @user2, item: @item2, amount: @item2.price, active: false)
  @blob3 = FactoryBot.create(:blob, user: @user3, item: @item3, amount: @item3.price, active: false)
 end

 def teardown
  DatabaseCleaner.clean
 end
end

然后是item.rb

class Item < ApplicationRecord
 after_create :create_blobs

 private
 def create_blobs
  blob = Blob.new(user_id: self.owner.id, item_id: self.id, amount: self.price)
  blob.save
 end
end

一点背景:User创建Item,然后在Blob中创建after_createamount参数设置为{1}} Item&#39; price。我无法找到如何在minitest中运行after_create,因此我在setup中模拟了Blob数据以继承Item的属性。

我可以看到错误来自item_test.rb的第15行,但我不明白为什么。我创建了Users,然后是Items,然后是 错误 Blobs。我理解为什么(我对用户和项目的组合有数据库级别唯一性约束)但不知道如何(因为从我看到的,我还没有创建那些Blobs - 那里&#39; s after_create在测试中创建Item时没有DatabaseCleaner.start,我怀疑这与我写这篇文章的方式有关。

我很自然地得出结论:DatabaseCleaner.cleanafter_create在测试运行和结束时都会启动并清理旧的测试数据,但显然情况并非如此。我开始专门用它来避免这个问题,这是我之前遇到的问题。所以我db:drop db:create和db:schema:load,但是我再次遇到同样的问题。如果不是这样,那就是对用户名,电子邮件等的唯一性违规......长话短说,这个错误发生了什么?

很抱歉,如果这太令人困惑了。

编辑:如果我取消注释blob并将所有通过该回调创建的blobs对象的方法引用替换为在我的测试设置中创建的{{1}},则测试通过。但我真的不喜欢这样做。

1 个答案:

答案 0 :(得分:0)

取消注释after_create并引用测试对象,或删除测试对象并通过编写返回blob owned_by用户和项的方法来引用每个blob,以便您可以编写@item.blob,让它返回相关的blob