[英]How do I validate and test the tandem creation of associated objects in Rails 4?
在我的應用中,初始化用戶后,我希望他們構建5個項目。 我見過斷言存在例如expect(@user.items.count).to eq(5)
..的測試。 但是,我一直在嘗試驗證項目的長度並測試驗證本身,而不是與用戶關聯的對象數。 這有可能嗎? 如果是這樣,最好的方法是什么?
這是我到目前為止的相關代碼。
class User < ActiveRecord::Base
ITEMS_ALLOWED = 5
has_many :items
validates :items, length: {is: ITEMS_ALLOWED}
after_initialize :init_items
def init_items
ITEMS_ALLOWED.times { items.build }
end
...
我的相關測試,使用RSpec,Faker和FactoryGirl
describe User do
before :each do
@user = build(:user, username: "bob")
@user.save
end
it "is invalid with more than 5 items" do
user3 = build(:user)
user3.save
expect(user3.items.create(name: "test")).not_to be_valid
end
end
當前,測試將嘗試驗證創建的項目。 我嘗試將驗證移至Item類,但是在嘗試調用user.items.count
的行上,我收到了錯誤的nil未定義方法項。
class Item < ActiveRecord::Base
belongs_to :user
validates :number_of_items, length: {is: 5}
def number_of_items
errors.add("User must have exactly 5 items.") unless user.items.count == 5
end
end
================更新:失敗消息,在Item類中沒有驗證時。
Failures:
1) User initialization is invalid with more than 5 items
Failure/Error: expect(user3.items.create(name: "test")).not_to be_valid
expected #<Item id: 16, name: "test", user_id: 3, photo: nil, created_at: "2014-01-14 00:24:11", updated_at: "2014-01-14 00:24:11", photo_file_name: nil, photo_content_type: nil, photo_file_size: nil, photo_updated_at: nil, description: nil> not to be valid
創建User
實例時,將init_items
並創建Item
實例。 但是,此時尚未定義用戶的id,因此創建的項的user_id
值為nil
。 依次導致表的user
方法在number_of_items
驗證中返回nil
。
當刪除Item
驗證時,RSpec示例將失敗,因為您正在對Item
進行驗證(即user3.items.create
的結果),而不是驗證結果User
。 相反,您可以執行以下操作:
user3.items.create(name: "test")
expect(user3).to_not be_valid
我會避免使用after_initialize
。 每當實例化對象時都會調用它,即使僅調用User.find
之后User.find
。 如果必須使用它,請為new_record?
添加測試new_record?
以便僅為新User
添加項目。
一種替代方法是編寫一個生成器方法來代替User.new使用。
class User < ActiveRecord::Baae
ITEMS_ALLOWED = 5
has_many :items
validates :items, length { is: ITEMS_ALLOWED }
def self.build_with_items
new.tap do |user|
user.init_items
end
end
def init_items
ITEMS_ALLOWED.times { items.build }
end
end
describe User do
context "when built without items" do
let(:user) { User.new }
it "is invalid" do
expect(user.items.size).to eq 0
expect(user.valid?).to be_false
end
end
context "when built with items" do
let(:user) { User.build_with_items }
it "is valid" do
expect(user.items.size).to eq 5
expect(user.valid?).to be_true
end
end
end
這可以讓你的項目從初始化用戶初始化分開,在你最終希望有一個情況下User
沒有項目。 以我的經驗,這比要求以相同方式構建所有新對象要好。 折衷方案是您現在需要在控制器的new
操作中使用User.build_with_items
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.