Mat*_*ves 15 ruby unit-testing
我正在浏览EdgeCase Ruby Koans.在about_dice_project.rb中,有一个名为"test_dice_values_should_change_between_rolls"的测试,这很简单:
def test_dice_values_should_change_between_rolls
dice = DiceSet.new
dice.roll(5)
first_time = dice.values
dice.roll(5)
second_time = dice.values
assert_not_equal first_time, second_time,
"Two rolls should not be equal"
end
Run Code Online (Sandbox Code Playgroud)
除了出现在那里的评论:
# THINK ABOUT IT:
#
# If the rolls are random, then it is possible (although not
# likely) that two consecutive rolls are equal. What would be a
# better way to test this.
Run Code Online (Sandbox Code Playgroud)
哪个(显然)让我思考:什么是可靠地测试随机事物的最佳方式(特别是,通常)?
Mar*_*sop 21
恕我直言,到目前为止,大多数答案都错过了Koan问题,除了@Super_Dummy.让我详细说明我的想法......
说不是骰子,而是掷硬币.添加另一个仅在我们的集合中使用一个硬币的约束,并且我们有一个可以生成"随机"结果的最小非平凡集.
如果我们想要检查翻转"硬币组"[在这种情况下是单个硬币]每次产生不同的结果,我们可以预期每个单独结果的值在统计基础上的50%相同.运行的是通过单元测试ñ迭代对于一些大型ñ只会行使PRNG.它没有告诉你关于两个结果之间的实际平等或差异的实质内容.
换句话说,在这个Koan中,我们实际上并不关心每个掷骰子的价值.我们真的更担心返回的卷实际上是不同卷的表示.检查返回的值是否不同只是一阶检查.
大部分时间都足够 - 但偶尔也会随机性地导致单元测试失败.这不是一件好事.
如果在两个连续卷返回相同结果的情况下,我们应该检查两个结果是否实际上由不同对象表示.这将允许我们在将来重构代码[如果需要],同时确信测试仍将始终捕获任何行为不正确的代码.
TL; DR?
def test_dice_values_should_change_between_rolls
dice = DiceSet.new
dice.roll(5)
first_time = dice.values
dice.roll(5)
second_time = dice.values
assert_not_equal [first_time, first_time.object_id],
[second_time, second_time.object_id], "Two rolls should not be equal"
# THINK ABOUT IT:
#
# If the rolls are random, then it is possible (although not
# likely) that two consecutive rolls are equal. What would be a
# better way to test this.
end
Run Code Online (Sandbox Code Playgroud)
dsi*_*cha 18
我想说测试任何涉及随机性的方法的最佳方法是统计学上的.循环运行你的骰子功能一百万次,将结果制成表格,然后对结果进行一些假设检验.一百万个样本应该给你足够的统计功效,几乎所有与正确代码的偏差都会被注意到.您希望演示两个统计属性:
您可以使用Pearson的卡方检验来测试骰子卷的频率是否近似正确. 如果您正在使用一个好的随机nunber生成器,例如Mersenne Twister(这是大多数现代语言的标准库中的默认语言,但不适用于C和C++),并且您没有使用以前卷的任何已保存状态除了Mersenne Twister发电机本身,那么您的卷筒可用于所有实用目的,彼此独立.
作为随机函数统计测试的另一个例子,当我将NumPy随机数生成器移植到D编程语言时,我对端口是否正确的测试是使用Kolmogorov-Smirnov测试来查看生成的数字是否与概率分布相匹配他们应该匹配.
tfw*_*ght 10
没有办法为随机性编写基于状态的测试.它们是矛盾的,因为基于状态的测试通过提供已知输入和检查输出来进行.如果您的输入(随机种子)未知,则无法进行测试.
幸运的是,你真的不想测试Ruby的rand实现,所以你可以使用mocha来预期它.
def test_roll
Kernel.expects(:rand).with(5).returns(1)
Diceset.new.roll(5)
end
Run Code Online (Sandbox Code Playgroud)
看来这里有2个单独的单位.首先,一个随机数发生器.第二,使用(P)RNG的"骰子"抽象.
如果你想对骰子抽象进行单元测试,那么模拟出PRNG调用,并确保它调用它们,并为你给出的输入返回一个合适的值,等等.
PRNG可能是您的库/框架/操作系统的一部分,因此我不打扰它进行测试.也许你会想要一个集成测试,看看它是否返回合理的值,但这是一个完整的"其他问题".
小智 6
不是比较值,而是比较object_id:
assert_not_equal first_time.object_id, second_time.object_id
Run Code Online (Sandbox Code Playgroud)
这假设其他测试将检查整数数组.
| 归档时间: |
|
| 查看次数: |
3786 次 |
| 最近记录: |