【问题标题】:What is the best practice when writing Perl tests that involve randomness?编写涉及随机性的 Perl 测试时,最佳实践是什么?
【发布时间】:2011-04-19 18:54:44
【问题描述】:

在对我的模块List::Gen 进行一些更新时,我决定添加一个->pick(num) 方法,该方法将从其源返回一个num 大小的随机元素列表。为了测试这一点,我使用srand 作为随机数生成器的种子,并进行了几个形式的测试:

srand 1234;
is $src->pick(5)->str, '3 6 1 7 9';

这一切在我当时使用的 Windows 机器上运行良好。但是,当我将项目转移到 Mac 工作站时,所有随机性测试都失败了,因为尽管具有相同的随机种子,rand 却产生了不同的结果。我认为这是来自 rand() 的不同底层 C 实现。

所以问题是,测试这些功能的最佳跨平台方法是什么?我应该用自己的重载rand 函数吗?我是否应该为使用rand 的函数构建挂钩以启用产生可预测输出的“测试”模式?还有其他方法吗?

我更喜欢包含核心 Perl 技术的答案,因为我试图保持模块的依赖树很小。

Test::RandomTest::MockRandom好像是CPAN的建议,有没有人有这些模块的经验?

【问题讨论】:

  • Test::MockRandom 允许您选择数字序列,这样您就不会受到系统差异的影响。有一次我需要随机输出并想对其进行单元测试。

标签: perl testing random srand


【解决方案1】:

我没有用过任何一种。

看起来 Test::Random 对您来说是一个更好的选择,因为您显然只是在测试中使用随机性,而不是在发布的代码中。使用起来应该会简单很多。

Test::MockRandom 模块强制 rand() 函数返回确定性序列。

【讨论】:

    【解决方案2】:

    您可以运行一些选择并确保它们不会都返回相同的东西。毕竟,这就是函数的目的。

    【讨论】:

      【解决方案3】:

      我更喜欢简单地封装环境依赖项并覆盖它以进行测试,称为Test Stub 的测试模式。测试存根还涵盖了其他间接输入,例如系统时间和文件句柄。这些都应该被解释为同一问题的不同形式,这就是为什么我认为 CPAN 对这个问题的解决方案不太好。

      应用于随机数域,我们有类似的东西:

      use strict;
      use warnings;
      
      package Foo;
      
      sub new {
          my ($class) = @_;
      
          return bless {} => $class;
      }
      
      sub get_random_number {
          return rand();
      }
      
      package main;
      use Test::MockObject::Extends;
      use Test::More tests => 1;
      
      my $foo = Test::MockObject::Extends->new( Foo->new() );
      $foo->set_series(get_random_number => 0.5, 0.001, 0.999);
      
      is( $foo->get_random_number, 0.5 );
      

      这使得被测系统保持不变,除了无论如何都应该进行的重构,但提供了控制点以将可预测的数据注入到测试中。 get_random_number 不会被测试覆盖,因此以检查时正确的方式编写它是至关重要的;对所依赖的系统资源的一次调用就是其中应该包含的所有内容。

      对于您的具体问题,您需要从pick 中排除对rand 的依赖,然后在List::Gen 的可测试版本中覆盖提取的方法。 Test::MockObject::Extends 非常适合这种需求。

      【讨论】:

        【解决方案4】:

        也许随机部分对您的测试无关紧要?

        通过测试可以检查以下内容:

        1. 是否 ->pick( X ) 返回 X 个元素?
        2. 所有 X 元素都是 $src 列表的一部分吗?
        3. 测试 0、1 等...
        4. (也许?)测试两个不同的 srand 种子返回不同的列表

        这基本上是您已经在做的事情,因为您正试图将 rand() 排除在等式之外。不妨一路走下去,测试你的函数是否符合它在锡上所说的那样。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-10-29
          • 2017-11-16
          相关资源
          最近更新 更多