【发布时间】:2014-04-29 02:12:03
【问题描述】:
我正在用一个典型的工厂测试一个典型的 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
优点:这是最接近我想要的;当地国家;确保没有碰撞。
缺点:冗长笨拙的语法。
赏金
Factory Girl 或 Minifacture 是否有更适合随机数据且不是序列的语法?
或者,如果有保存冲突,也许某种模式可以自动重新掷骰子?
一些开销对我来说很好。实际上,在具有数千个测试的持续集成设置中,每天大约会发生一次冲突。如果测试套件必须重新掷骰子几次,或者探测数据库中的现有值等,那很好。
cmets 询问为什么随机数据而不是序列。我更喜欢随机数据,因为我的经验是随机数据可以带来更好的测试、更好的长期可维护性以及更好的测试目标语义。另外,我使用 Faker 和 Forgery 而不是固定装置,以防万一了解。
要获得赏金,答案必须是即时随机的,而不是顺序。 (例如,我正在寻找的解决方案可能使用#sample 和/或无序集,并且可能不使用#shuffle 和/或有序集)
【问题讨论】:
-
随机数据相对于序列有什么优势?测试中的随机数据可能会导致间歇性故障,并且难以诊断或重现。
-
也想知道随机的原因。对于序列,您可以 100% 确信您可以拥有 AAA 到 ZZZ 的唯一数据而不会发生冲突。但是对于随机,您要么创建一个不会发生冲突的随机生成器(这可能还是容易?),或者检查生成的数据(性能缓慢)
-
也许你想看看 Faker (github.com/stympy/faker) - 你可以使用 Faker::Lorem.characters(3) 并将它们转换为大写字母进行测试。
-
感谢 George & Peter & George;我添加了更多细节,是的,我正在使用 Faker。
-
我不知道你想要达到什么目的。如果你想要“随机”数据,faker 应该足够好。如果您不希望发生冲突,请使用序列,那应该就足够了。在最坏的情况下,您可以将 faker 和序列结合起来以始终生成“随机”数据。
标签: ruby-on-rails ruby rspec factory-bot minitest