Test::MockTime 在某些情况下不模拟时间

Test::MockTime does not mock time in certain cases

我有一个非常简单的脚本,它使用 Test::MockTime 模拟时间,但 time 调用的输出在代码的两部分中是不同的。 这是脚本:

package mocker;

use strict;
use warnings;

sub abcd {
    print "in abcd, time is " . time . "\n";
}

BEGIN {
    use Test::MockTime qw(set_absolute_time restore_time);
    set_absolute_time(0);
};

sub do_mock {
    print "Current epoch in do_mock is: " . time . "\n";
    abcd;
    restore_time();
}

1;

我在脚本中调用 mocker::do_mock

use strict;
use warnings;

use mocker;

mocker::do_mock;

我希望在两个打印语句中输出的当前时间为“0”,但奇怪的是我有这样的输出:

Current epoch in do_mock is: 0
in abcd, time is 1450343385

那么,为什么在abcd时间恢复到当前时间?

您可以查看 this answer 以更好地了解 BEGIN 块的工作原理。

这里的重点是它在主体之前执行,但它也必须编译。这意味着您放置声明和 BEGIN 块的顺序是相关的。

Test::MockTime 的 documentation 解释说 "it overrides localtime, gmtime and time at compile time." 所以:

print "Before: " . time; # Uses CORE::time()

use Test::MockTime;      # Override time()

print "After: " . time;  # Uses overridden time()

您可以使用 B::Deparse 查看此内容:

$ perl -MO=Deparse foo
print 'Before: ' . time;
use Test::MockTime;
print 'After: ' . &CORE::GLOBAL::time();
foo syntax OK

time() 的第二次调用实际上使用了 CORE::GLOBAL::time(),这是覆盖的版本。


要修复,请确保在调用 time() 之前编译 Test::MockTime:

package mocker;

use strict;
use warnings;

use Test::MockTime qw(set_absolute_time restore_time);

sub abcd {
    print "in abcd, time is " . time . "\n";
}

BEGIN {
    set_absolute_time(0);
};

sub do_mock {
    print "Current epoch in do_mock is: " . time . "\n";
    abcd;
    restore_time();
}

1;