我正在测试一个典型的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
我正在添加更多的测试,并开始看到机场代码冲突:例如工厂使用代码“XYZ”创建一个机场,然后对工厂的后续调用尝试创建具有相同代码的机场。
一种解决方法是使用序列。例如使用Factory Girl序列、有序列表、预先计算的枚举或者维护下一个可用代码状态的类似方式。
我的问题是:有哪些非序列化的方法可以解决这个问题?我想使用随机数据,而不是序列。
以下是我正在尝试的一些实用的想法-如果您能提供任何见解,将不胜感激。
使用乐观锁定的示例思路。
while
airport = Factory.build :airport
airport.save && return airport
end
优点:因为碰撞很少,实际速度快;本地状态。
缺点:语法笨拙;不局限于工厂;保存可能失败,原因不仅是碰撞。
使用事务的示例构想
Airport.transaction
while
x = random_airport_code
if Airport.exists?(code: x)
next
else
Factory :airport, code: x
break
end
end
end
优点:这是最接近我想要的;本地状态;确保没有冲突。
缺点:语法冗长而尴尬。
Bounty
Factory Girl或Minifacture是否有更适合随机数据而非顺序的任何语法?
或者,是否有一种模式可以自动重新投掷骰子,如果存在保存冲突?
对我来说,有些额外开销是可以接受的。在实践中,每天在数千个测试的持续集成设置中发生一次冲突左右。如果测试套件必须重新投掷几次骰子,或者探测数据库中已存在的值等,那就没关系。
评论问为什么使用随机数据而不是序列。我更喜欢随机数据,因为我的经验是随机数据可以带来更好的测试、更好的长期可维护性和更好的测试目标语义。此外,我使用Faker和Forgery代替固定装置,如果这有助于了解的话。
要获得赏金,答案必须是随机生成 - 不是一个序列。(例如,我正在寻找的解决方案可能会使用#sample和/或无序集合,并且可能不使用#shuffle和/或有序集合)
1.upto(3).inject("") { |m, e| m << (rand(26)+65).chr}
- zetetic