有没有办法在单元测试中覆盖Perl“使用常量”?

时间:2009-07-01 15:28:38

标签: perl unit-testing

我有一个Perl模块,我声明了一些常量:

use constant BASE_PATH => "/data/monitor/";

在实时操作中,常量永远不会改变,但我希望能够修改它 在我的单元测试中,例如将其设置为 〜/ project / testdata / 。有没有办法做到这一点 不必使用“非常数”?

我可以在constant.pm上使用 Test :: MockObject 吗?

5 个答案:

答案 0 :(得分:6)

当使用常量时,它们被实现为常量函数,其行为类似于:

use subs 'BASE_PATH';
sub BASE_PATH () {"/data/monitor/"}

程序中BASE_PATH的任何使用都是内联的,因此无法修改。

为了达到类似的目的,您可以手动使用subs pragma(使BASE_PATH表现为内置函数)并将BASE_PATH声明为标准函数:

use subs 'BASE_PATH';
sub BASE_PATH {"/data/monitor/"}

print "BASE_PATH is ".BASE_PATH."\n";

*BASE_PATH = sub {"/new/path"};
print "BASE_PATH is ".BASE_PATH."\n";

虽然你为什么要这样做但我不太确定。

答案 1 :(得分:6)

测试经常揭示设计的不灵活性。这是其中一次。那个常数不应该是恒定的。

如果你出于性能原因这样做,我愿意用坚硬的货币押注它没有任何区别。

答案 2 :(得分:3)

unconstant

一种简单的方法是使用unconstant

# From ./lib/Foo.pm
package Foo {
    use constant BASE_PATH => '/data/monitor/';
}


# From test.pl
use unconstant;  # Do this first
use Foo;
use constant *Foo::BASE_PATH => '/otherData/otherMonitor/';

免责声明:我是unconstant的作者,但是我遇到了同样的问题。

答案 3 :(得分:2)

package My::Class;

use constant BASE_PATH => "/a/real/value/";

# ..more code here..

1;

现在进行单元测试:

use My::Class;
*{My::Class::BASE_PATH} = sub { "/a/fake/value" };

# do your tests here...

答案 4 :(得分:1)

显然,如果您的测试确实改变了它,那么您的BASE_PATH定义被用于/编译到另一个子例程中(通过

*BASE_PATH = sub { ... }

或其他东西)你没有解决方案(因为当原始模块使用BASE_PATH作为常量时,它确实定义了一个INLINE函数,当在其他代码中使用时,它已内联)