如何使用rspec测试随机唯一值

时间:2013-08-23 18:28:37

标签: ruby-on-rails rspec

我有这段代码:

def self.generate_random_uniq_code
  code = sprintf("%06d", SecureRandom.random_number(999999))
  code = self.generate_random_uniq_code if self.where(code: code).count > 0
  code
end

目标是为新寄存器创建随机代码,代码不能存在于寄存器中 我正在尝试这种方式,但是当我模拟SecureRandom时,它总是返回相同的值:

it "code is unique" do
  old_code = Code.new
  old_code.code = 111111
  new_code = Code.new
  expect(SecureRandom).to receive(:random_number) {old_code.code}
  new_code.code = Code.generate_random_uniq_code
  expect(new_code.code).to_not eq old_code.code
end

我试图找到是否有办法启用和禁用模拟行为,但我找不到它,我不确定我是否正确地进行测试,代码似乎无法正常工作我。 欢迎任何帮助,谢谢!

1 个答案:

答案 0 :(得分:3)

TL; DR

通常,除非您实际测试的是您编写的PRNG,否则您可能会测试错误的行为。考虑一下您实际尝试测试的行为,并检查您的替代方案。此外,六位数的数字并没有足够的密钥空间来确保大多数用途的真正随机性,因此您可能需要考虑更强大的内容。

一些替代品

应始终测试行为,而不是实施。以下是一些需要考虑的替代方案:

  1. 使用UUID代替六位数字。与当前解决方案相比,UUID遇到statistically less likely碰撞。
  2. adjusting the schema在数据库列中强制实现唯一性。
  3. 在模型中使用Rails uniqueness validator
  4. 使用FactoryGirl sequences或lambdas返回测试值。
  5. 修复您的规范

    如果你真的坚持测试这段代码,你至少应该使用正确的期望。例如:

    # This won't do anything useful, if it even runs.
    expect(new_code.code).to_not  old_code.code
    

    相反,你应该检查是否相等,如下所示:

    old_code = 111111
    new_code = Code.generate_random_uniq_code
    new_code.should_not eq old_code
    

    您的代码可能会以其他方式被破坏(例如,您方法中的代码变量似乎不是实例或类变量)所以我不能保证以上方法可行,但至少应该指向正确的方向。