6

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

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

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

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

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

Test::RandomTest::MockRandom似乎是 CPAN 的建议,有人对这些模块有经验吗?

4

4 回答 4

2

我没有使用任何一种。

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

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

于 2011-04-19T19:01:48.937 回答
0

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

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

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

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

于 2011-04-20T10:43:41.120 回答
0

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

对于您的特定问题,您需要考虑对randout of的依赖关系pick,然后在可测试版本中覆盖提取的方法List::GenTest::MockObject::Extends非常适合这种需求。

于 2011-04-19T21:13:28.133 回答
0

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

于 2011-04-19T19:32:58.313 回答