测试这个的最佳方法是什么?

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

我想说测试任何涉及随机性的方法的最佳方法是统计学上的.循环运行你的骰子功能一百万次,将结果制成表格,然后对结果进行一些假设检验.一百万个样本应该给你足够的统计功效,几乎所有与正确代码的偏差都会被注意到.您希望演示两个统计属性:

  1. 每个值的概率都是您的预期.
  2. 所有卷都是相互独立的事件.

您可以使用Pearson的卡方检验来测试骰子卷的频率是否近似正确. 如果您正在使用一个好的随机nunber生成器,例如Mersenne Twister(这是大多数现代语言的标准库中的默认语言,但不适用于C和C++),并且您没有使用以前卷的任何已保存状态除了Mersenne Twister发电机本身,那么您的卷筒可用于所有实用目的,彼此独立.

作为随机函数统计测试的另一个例子,当我将NumPy随机数生成器移植到D编程语言时,我对端口是否正确的测试是使用Kolmogorov-Smirnov测试来查看生成的数字是否与概率分布相匹配他们应该匹配.

  • +1以非常禅的方式展示测试随机性的徒劳无益. (4认同)
  • @sarah,zen!=非常,非常干燥...非常禅的反应就像"你怎么能确定明天太阳会升起?" (2认同)

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)


Ken*_*Ken 7

看来这里有2个单独的单位.首先,一个随机数发生器.第二,使用(P)RNG的"骰子"抽象.

如果你想对骰子抽象进行单元测试,那么模拟出PRNG调用,并确保它调用它们,并为你给出的输入返回一个合适的值,等等.

PRNG可能是您的库/框架/操作系统的一部分,因此我不打扰它进行测试.也许你会想要一个集成测试,看看它是否返回合理的值,但这是一个完整的"其他问题".

  • 存根随机数生成器并让它返回常量值。编写测试只是为了验证它调用随机数。验证数字实际上是“随机的”是徒劳的。 (2认同)

小智 6

不是比较值,而是比较object_id:

    assert_not_equal first_time.object_id, second_time.object_id
Run Code Online (Sandbox Code Playgroud)

这假设其他测试将检查整数数组.