【问题标题】:Best practice: testing code which uses a random number generator最佳实践:测试使用随机数生成器的代码
【发布时间】:2014-02-07 10:24:17
【问题描述】:

在代码中的某处(深、深)说我正在使用随机数来做一些很酷的事情。测试通常应该是确定性的,而这部分代码的发布版本的行为明确利用了随机数生成器的非确定性/随机性。

所以为了获得确定性(功能)测试,我想设置一个固定的种子值:

size_t seed = 42;
std::mt19937 rng;
rng.seed(seed);

但我也想确保当我使用随机输入和随机种子时不会发生任何奇怪的事情(即异常):

std::mt19937 rng;
rng.seed(std::random_device()());

显然,有限数量的测试运行无法确定代码是否正确;但是,大量的试运行至少可以给你一些信心。

如何最好地处理这个问题?我想添加类似的东西:

size_t seed = std::random_device()();
#ifdef TESTING
    seed = 42;
#endif
rng.seed(seed);

但是,我不能有一个测试文件(使用 gtest)对某些测试使用随机种子,而对其他一些测试使用恒定种子(可以吗?)。

¹在我的例子中:我从 n 中均匀且独立地随机选择一个元素来对输入进行分区。

编辑:我问的是功能测试,而不是单元测试。

【问题讨论】:

  • 给定一个特定的种子,你的生成器可能是完全确定的

标签: c++ testing random


【解决方案1】:

首先,为随机数生成器创建一个接口,以便测试能够将其替换为预定义的。如果您在单元测试中使用随机数生成器,则它不再是单元。

然后想想你真正想测试什么。我想,应该测试这个算法:

  • 它是否有效(您预定义的“随机”生成器可能会在每次迭代时返回 1、2、3、... - 可能以最大范围为模);
  • 如果随机生成器总是返回边界值(0 和 max-1 或 max,取决于您的需要),是否返回有效结果;
  • 如果随机生成器返回的值超出范围,是否通知错误。


编辑:(回应问题编辑)

您为什么要在功能测试中使用随机数生成器?功能测试检查应用程序在用户使用时是否正常工作。用户将无法访问随机数生成器的种子,因此请保持原样并让它按照您的设计工作。如果您的算法的结果不依赖于随机数生成器生成的值,请检查它们是否在测试之间没有变化。如果它们确实依赖于随机数生成器,请检查 if 它们在两个测试之间发生了变化(如果它们没有变化,这意味着代码没有做它应该做的事情应该)。

【讨论】:

  • 抱歉,我的问题不够精确:我问的是功能测试,而不是单元测试。
【解决方案2】:

这取决于你想做什么样的测试。

在单元测试中,种子应设置为固定值。

在某种功能测试中,您确实想使用随机数来测试行为,并且无论需要多长时间,您都可以设置随机种子(可能使用 time()),然后执行尽可能多地测试。

这意味着,您应该以类似的方式(使用 gtest)创建两组测试,其中单元测试的执行速度会更快。使用单元测试,您不会访问文件和缓慢的资源(如网络和数据库)。

【讨论】:

  • 这就是我在我的问题中所说的。真正的问题是:假设我不能轻易传递种子,使用#define 是个好主意吗?
  • @mort 不确定你是否真的理解我的回答。使用此设置,您不必使用宏。当然,您可以根据某些宏有条件地编译某些代码。没关系,只要你只有几个这样的宏。
猜你喜欢
  • 2017-03-23
  • 2010-11-11
  • 2010-09-20
  • 2013-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-11
相关资源
最近更新 更多