如何用RSpec测试`rand()`?

kon*_*gun 21 ruby unit-testing rspec ruby-on-rails

我有一个类似这样的方法:

def some_method
  chance = rand(4)
  if chance == 1 do
    # logic here
  else
    # another logic here
  end
end
Run Code Online (Sandbox Code Playgroud)

当我使用RSpec来测试这个方法时,rand(4)它内部总是生成0.我没有测试randRails的方法,我正在测试我的方法.测试我方法的常见做法是什么?

Nei*_*ter 34

我会考虑两种方法:

方法1:

srand( seed )before :each块中使用已知的种子值:

before :each do
  srand(67809)
end
Run Code Online (Sandbox Code Playgroud)

这适用于Ruby版本,并在您想要涵盖特定组合的情况下为您提供控制.我经常使用这种方法 - 考虑一下,这是因为我测试的代码rand()主要用作数据源,而第二次(如果有的话)用于分支.它也被调用了很多,因此对返回值进行逐个调用控制会适得其反,我最终会铲掉许多"看起来随机"的测试数据,可能首先通过调用生成它rand()!

您可能希望在至少一个测试场景中多次调用您的方法,以确保您有合理的组合覆盖率.

方法2:

如果由于输出的值而有分支点,rand()并且你的断言属于"如果它选择X,那么Y应该发生"的类型,那么在同一个测试套件中模拟输出rand( n )返回你想要的值的东西也是合理的做出断言:

 require 'mocha/setup'

 Kernel.expects(:rand).with(4).returns(1)
 # Now run your test of specific branch
Run Code Online (Sandbox Code Playgroud)

从本质上讲,这些都是"白盒子"测试方法,它们都要求您知道您的例程在rand()内部使用.

"黑匣子"测试要困难得多 - 您需要断言行为在统计上是正常的,并且您还需要接受非常广泛的可能性,因为有效的随机行为可能会导致幻像测试失败.

  • 另见http://stackoverflow.com/questions/6077725/ruby-using-rand-in-code-but-writing-tests-to-verify-probabilities (2认同)

Ste*_*fan 14

我提取随机数生成:

def chance
  rand(4)
end

def some_method
  if chance == 1 do
    # logic here
  else
    # another logic here
  end
end
Run Code Online (Sandbox Code Playgroud)

它存根:

your_instance.stub(:chance) { 1 }
Run Code Online (Sandbox Code Playgroud)

这不会将测试与实现细节联系起来,rand如果您决定使用另一个随机数生成器,则测试不会中断.


sam*_*uil 12

似乎最好的想法是使用stub而不是real rand.这样您就可以测试您感兴趣的所有值.正如模块中rand定义的那样,Kernel您应该使用以下方法对其进行存根:

Kernel.stub(:rand).with(anything) { randomized_value }
Run Code Online (Sandbox Code Playgroud)

在特定的上下文中,您可以randomized_value使用let方法定义.

  • 使用新的rspec语法,这相当于`allow(Kernel).to receive(:rand).and_return(0.5)` (2认同)

Obr*_*ios 6

我发现只是短暂的兰德即.使用Kernel.stub(:rand)作为Samuil的回答并没有最初的工作.我要测试的代码直接调用rand,例如

random_number = rand

但是,如果我将代码更改为

random_number = Kernel.rand

然后茬工作了.