我有一个方法可以做这样的事情:
def some_method
chance = rand(4)
if chance == 1 do
# logic here
else
# another logic here
end
end
当我使用 RSpec 测试这个方法时,rand(4)
它里面总是生成 0。我不是在测试rand
Rails 的方法,我是在测试我的方法。测试我的方法的常见做法是什么?
我有一个方法可以做这样的事情:
def some_method
chance = rand(4)
if chance == 1 do
# logic here
else
# another logic here
end
end
当我使用 RSpec 测试这个方法时,rand(4)
它里面总是生成 0。我不是在测试rand
Rails 的方法,我是在测试我的方法。测试我的方法的常见做法是什么?
我会考虑两种方法:
方法1:
srand( seed )
在块中使用已知的种子值before :each
:
before :each do
srand(67809)
end
这适用于 Ruby 版本,并在您想要涵盖特定组合的情况下为您提供控制。我经常使用这种方法——仔细想想,那是因为我正在测试的代码rand()
主要用作数据源,其次才(如果有的话)用于分支。它也被调用了很多,因此对返回值进行逐个调用控制会适得其反,我最终会铲入大量“看起来随机”的测试数据,可能首先通过调用来生成它rand()
!
您可能希望在至少一个测试场景中多次调用您的方法,以确保您有合理的组合覆盖率。
方法二:
如果由于输出的值而具有分支点,并且您的断言属于“如果它选择 X,则 Y 应该发生”的类型,那么在同一个测试套件中模拟返回您想要的值的东西rand()
也是合理的rand( n )
断言:
require 'mocha/setup'
Kernel.expects(:rand).with(4).returns(1)
# Now run your test of specific branch
本质上,这些都是“白盒”测试方法,它们都要求您知道您的例程在rand()
内部使用。
“黑盒”测试要困难得多——您需要断言行为在统计上是正常的,并且您还需要接受非常广泛的可能性,因为有效的随机行为可能导致幻像测试失败。
我会提取随机数生成:
def chance
rand(4)
end
def some_method
if chance == 1 do
# logic here
else
# another logic here
end
end
并存根:
your_instance.stub(:chance) { 1 }
这不会将您的测试与实现细节联系起来,rand
如果您决定使用另一个随机数生成器,您的测试不会中断。
似乎最好的主意是使用 stub 而不是 real rand
。这样你就可以测试你感兴趣的所有值。正如模块rand
中定义的那样,Kernel
你应该使用:
Kernel.stub(:rand).with(anything) { randomized_value }
在特定情况下,您可以randomized_value
使用let
方法定义。
我发现这只是存根 rand ie。使用 Samuil 回答的 Kernel.stub(:rand) 最初不起作用。我要测试的代码直接称为 rand 例如
随机数 = 兰德
但是,如果我将代码更改为
random_number = Kernel.rand
然后存根工作。
这适用于 RSpec:
allow_any_instance_of(Object).to receive(:rand).and_return(1)