Mar*_*ric 40 ruby unit-testing ruby-on-rails fixtures factory-bot
我正在使用Rails 2.2项目来更新它.我正在用工厂替换现有的灯具(使用factory_girl)并且遇到了一些问题.问题在于表示具有查找数据的表的模型.当我创建一个包含两个具有相同产品类型的产品的购物车时,每个创建的产品都会重新创建相同的产品类型.这是ProductType模型上唯一验证的错误.
这是一个单元测试,我创建一个Cart并将它们组合在一起.我不得不这样做以解决问题.但这仍然证明了这个问题.我会解释一下.
cart = Factory(:cart)
cart.cart_items = [Factory(:cart_item,
:cart => cart,
:product => Factory(:added_users_product)),
Factory(:cart_item,
:cart => cart,
:product => Factory(:added_profiles_product))]
Run Code Online (Sandbox Code Playgroud)
添加的两个产品属于同一类型,每个产品创建时都会重新创建产品类型并创建重复项.
生成的错误是:"ActiveRecord :: RecordInvalid:验证失败:名称已被占用,代码已被占用"
此示例的解决方法是覆盖正在使用的产品类型并传入特定实例,因此只使用一个实例."add_product_type"提前获取并传入每个购物车项目.
cart = Factory(:cart)
prod_type = Factory(:add_product_type) #New
cart.cart_items = [Factory(:cart_item,
:cart => cart,
:product => Factory(:added_users_product,
:product_type => prod_type)), #New
Factory(:cart_item,
:cart => cart,
:product => Factory(:added_profiles_product,
:product_type => prod_type))] #New
Run Code Online (Sandbox Code Playgroud)
使用factory_girl与"pick-list"类型的关联的最佳方法是什么?
我喜欢为厂家定义为包含,而不必进行组装测试的一切,虽然我可以住在一起.
工厂/ product.rb
# Declare ProductTypes
Factory.define :product_type do |t|
t.name "None"
t.code "none"
end
Factory.define :sub_product_type, :parent => :product_type do |t|
t.name "Subscription"
t.code "sub"
end
Factory.define :add_product_type, :parent => :product_type do |t|
t.name "Additions"
t.code "add"
end
# Declare Products
Factory.define :product do |p|
p.association :product_type, :factory => :add_product_type
#...
end
Factory.define :added_profiles_product, :parent => :product do |p|
p.association :product_type, :factory => :add_product_type
#...
end
Factory.define :added_users_product, :parent => :product do |p|
p.association :product_type, :factory => :add_product_type
#...
end
Run Code Online (Sandbox Code Playgroud)
ProductType的"代码"的目的是使应用程序可以赋予它们特殊的含义.ProductType模型如下所示:
class ProductType < ActiveRecord::Base
has_many :products
validates_presence_of :name, :code
validates_uniqueness_of :name, :code
#...
end
Run Code Online (Sandbox Code Playgroud)
工厂/ cart.rb
# Define Cart Items
Factory.define :cart_item do |i|
i.association :cart
i.association :product, :factory => :test_product
i.quantity 1
end
Factory.define :cart_item_sub, :parent => :cart_item do |i|
i.association :product, :factory => :year_sub_product
end
Factory.define :cart_item_add_profiles, :parent => :cart_item do |i|
i.association :product, :factory => :add_profiles_product
end
# Define Carts
# Define a basic cart class. No cart_items as it creates dups with lookup types.
Factory.define :cart do |c|
c.association :account, :factory => :trial_account
end
Factory.define :cart_with_two_different_items, :parent => :cart do |o|
o.after_build do |cart|
cart.cart_items = [Factory(:cart_item,
:cart => cart,
:product => Factory(:year_sub_product)),
Factory(:cart_item,
:cart => cart,
:product => Factory(:added_profiles_product))]
end
end
Run Code Online (Sandbox Code Playgroud)
当我尝试使用相同产品类型的两个项目定义购物车时,我得到上述相同的错误.
Factory.define :cart_with_two_add_items, :parent => :cart do |o|
o.after_build do |cart|
cart.cart_items = [Factory(:cart_item,
:cart => cart,
:product => Factory(:added_users_product)),
Factory(:cart_item,
:cart => cart,
:product => Factory(:added_profiles_product))]
end
end
Run Code Online (Sandbox Code Playgroud)
Cub*_*bre 45
仅供参考,您也可以使用initialize_with工厂内的宏并检查对象是否已存在,然后再不创建它.使用lambda的解决方案(很棒,但是!)正在复制find_or_create_by中已存在的逻辑.这也适用于通过相关工厂创建联盟的协会.
FactoryGirl.define do
factory :league, :aliases => [:euro_cup] do
id 1
name "European Championship"
rank 30
initialize_with { League.find_or_create_by_id(id)}
end
end
Run Code Online (Sandbox Code Playgroud)
d2v*_*vid 31
我遇到了同样的问题,并在我的工厂文件的顶部添加了一个实现单例模式的lambda,如果自上一轮测试/规范以来数据库已被清除,它还会重新生成模型:
saved_single_instances = {}
#Find or create the model instance
single_instances = lambda do |factory_key|
begin
saved_single_instances[factory_key].reload
rescue NoMethodError, ActiveRecord::RecordNotFound
#was never created (is nil) or was cleared from db
saved_single_instances[factory_key] = Factory.create(factory_key) #recreate
end
return saved_single_instances[factory_key]
end
Run Code Online (Sandbox Code Playgroud)
然后,使用示例工厂,您可以使用factory_girl惰性属性来运行lambda
Factory.define :product do |p|
p.product_type { single_instances[:add_product_type] }
#...this block edited as per comment below
end
Run Code Online (Sandbox Code Playgroud)
瞧!
| 归档时间: |
|
| 查看次数: |
14964 次 |
| 最近记录: |