joe*_*son 9 ruby rspec ruby-on-rails minitest factory-bot
我正在使用典型工厂测试典型的Rails模型:
# My model uses a 3-letter uppercase airport code,
# such as "ATL" for Atlanta, "BOS" for Boston, etc.
class Airport < ActiveRecord::Base
validates :code, uniqueness: true
Factory.define :airport do |f|
f.code { random_airport_code } # Get a 3-letter uppercase code
Run Code Online (Sandbox Code Playgroud)
我正在添加更多测试并开始在机场代码中看到碰撞:例如工厂创建一个代码为"XYZ"的机场,然后工厂的后续调用尝试创建具有相同代码的机场.
序列是解决这个问题的一种方法.例如,使用Factory Girl序列,有序列表或预先计算的枚举,一些类似的方式来维护下一个可用代码的状态.
我的问题是:什么是非序列方法来解决这个问题?我想使用随机数据,而不是序列.
我正在尝试的一些想法因为它们是务实的 - 对这些的任何见解都非常感激.
while
airport = Factory.build :airport
airport.save && return airport
end
Run Code Online (Sandbox Code Playgroud)
优点:实践快速,因为碰撞很少见; 当地的州.
缺点:笨拙的语法; 非本地工厂; 由于碰撞以外的原因,保存可能会失败.
Airport.transaction
while
x = random_airport_code
if Airport.exists?(code: x)
next
else
Factory :airport, code: x
break
end
end
end
Run Code Online (Sandbox Code Playgroud)
优点:这是我最想要的; 地方国家; 确保没有碰撞.
缺点:漫长的尴尬语法.
Factory Girl或Minifacture是否有任何类型的语法更适合随机数据,而不是序列?
或者,如果存在保存冲突,可能会有某种模式自动重新掷骰子?
一些开销对我很好.实际上,每天都会发生一次碰撞,在数千次测试的持续集成设置中.如果测试套件必须重新掷骰子几次,或探测数据库中的现有值等,那很好.
评论询问为什么随机数据而不是序列.我更喜欢随机数据,因为我的经验是随机数据可以带来更好的测试,更好的长期可维护性以及更好的语义和测试目标.此外,我使用Faker和Forgery代替灯具,以防有助于了解.
要获得赏金,答案必须是随机的 - 而不是序列.(例如,我正在寻找的解决方案可能使用#sample和/或无序集合,并且可能不会使用#shuffle和/或有序集合)
你可以使用回调.就像是:
factory :airport do
after(:build) do |airport|
airport.code = loop do
code = ('AAA'..'ZZZ').to_a.sample
break code unless Airport.exists?(code: code)
end
end
end
Run Code Online (Sandbox Code Playgroud)
您可能想要更改after(:build)为before(:create),这取决于您希望如何使用工厂.
是的,FactoryGirl 有一个功能可以让您做到这一点。请参阅序列文档的末尾:https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#sequences您可以将序列设置为任何知道如何在 # 时返回自身增量版本的对象。接下来是调用它。因此,您可以编写一个知道如何返回唯一随机数据并实现#next 的类,例如
class AirportCode
ALL = %w(AAA BBB CCC).shuffle
attr_reader :index
def initialize(index = rand(ALL.length))
@index = index
end
def value
ALL[@index]
end
def to_s
value
end
# might need to explicitly delegate more methods to the value
def method_missing(method, *args)
value.send method, *args
end
def next
AirportCode.new((index + 1) % ALL.length)
end
end
Run Code Online (Sandbox Code Playgroud)
(这个只有三个唯一值,但这只是为了说明这一点),创建一个 FactoryGirl 序列并将其值设置为该类的一个实例。我没有尝试 FactoryGirl 部分,所以请报告它是否有效:)
| 归档时间: |
|
| 查看次数: |
1707 次 |
| 最近记录: |