编写涉及随机性的Perl测试时,最佳做法是什么?

时间:2011-04-19 18:54:44

标签: perl testing random srand

在处理模块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的建议,有没有人有这些模块的经验?

4 个答案:

答案 0 :(得分:2)

我没有用过任何一个。

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

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

答案 1 :(得分:0)

你可以运行几个选择,并确保他们不会返回相同的东西。毕竟,这就是这个功能的目的。

答案 2 :(得分:0)

我更喜欢简单地封装环境依赖关系并将其覆盖以用于测试目的,称为Test Stub的测试模式。 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不会被测试所覆盖,因此以正确的检查方式编写它是至关重要的;对依赖系统资源的单次调用就是应该存在的所有内容。

如果您遇到特定问题,则需要将rand的依赖关系从pick中分解出来,然后在List::Gen的可测试版本中覆盖提取的方法。 Test::MockObject::Extends非常适合这种需要。

答案 3 :(得分:0)

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

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

  1. did - > pick(X)返回X元素?
  2. 所有X元素都是$ src列表的一部分吗?
  3. 测试0,1等......
  4. (也许?)测试两个不同的srand种子返回不同的列表
  5. 这基本上就是你已经在做的事情,因为你试图将rand()排除在等式之外。也可以一路走下去,测试你的功能是否符合它所说的那样。