代码之家  ›  专栏  ›  技术社区  ›  ijw

如何使用不断变化的系统时间测试Perl应用程序?

  •  2
  • ijw  · 技术社区  · 16 年前

    我有一个web应用程序,我想在上面运行一些系统测试,为了做到这一点,我需要调整系统时间。应用程序一直使用DateTime。

    有人对如何更改DateTime的时间有什么建议吗?>现在报告?我唯一想到的是对DateTime进行子类化,并弄乱所有的“use”行,但这似乎相当具有侵入性。

    关于答案的说明:

    使用它;以及(c)Hook::LexWrap只是比符号表中的黑客更优雅,尽管它做了同样的事情。(此外,它是我已经安装的一些模块的依赖项,所以我甚至不必对其进行CPAN……)

    4 回复  |  直到 16 年前
        1
  •  1
  •   daotoad    16 年前

    而不是采取高层次的方法和包装 DateTime 具体来说,您可能希望查看这些模块 Test::MockTime Time::Mock ,它覆盖了低级功能 日期时间 等。利用它,(如果幸运的话)会做正确的事 任何 时间敏感代码。在我看来,这似乎是一种更稳健的测试方法。

        2
  •  11
  •   hobbs    16 年前

    我认为Hook::LexWrap在这种情况下太过分了。重新定义这样一个简单的函数更容易。

    use DateTime;
    
    my $offset;
    
    BEGIN {
      $offset = 24 * 60 * 60; # Pretend it's tomorrow
    
      no warnings 'redefine';
    
      sub DateTime::now
      {
        shift->from_epoch( epoch => ($offset + scalar time), @_ )
      }
    } # end BEGIN
    

    您可以替换 my $offset 随着 our $offset 如果您需要访问 $offset 从包含此代码的文件外部。

    您可以调整 $抵消 在任何时候,如果你想在运行期间更改DateTime对当前时间的看法。

    计算 $抵消 应该比上面显示的更复杂。例如,要将“当前时间”设置为绝对时间:

    my $want = DateTime->new(
       year   => 2009,
       month  => 9,
       day    => 14,
       hour   => 12,
       minute => 0,
       second => 0,
       time_zone => 'America/Chicago',
    );
    
    my $current = DateTime->from_epoch(epoch => scalar time);
    
    $offset = $want->subtract_datetime_absolute($current)->in_units('seconds');
    

    但你可能确实想计算一个固定的秒数,加到当前时间上,这样时间在那之后就会正常前进。使用问题 add( days => 1 ); 在重新定义 now 方法是,像DST变化这样的事情会导致时间在错误的伪时间跳跃。

        3
  •  4
  •   cjm    16 年前

    您可以通过以下方式使用代码注入 Hook::LexWrap 拦截now()方法。

    use Hook::LexWrap;
    
    use DateTime;
    
    # Use real now
    test();
    
    {
        my $wrapper = wrap 'DateTime::now',
            post => sub {
                $_[-1] = DateTime->from_epoch( epoch => 0 );
            };
    
        # Use fake now
        test();
    
    }
    
    # use real now again
    test();
    
    sub test {
        my $now = DateTime->now;
    
        print "The time is $now\n";
    }
    
        4
  •  1
  •   Unk    14 年前

    在设计一个考虑到可测试性的新类时,理想的解决方案是能够注入新的日期对象。

    但是,对于使用 DateTime->now DateTime->today 下面是一个可能的、范围适当的解决方案。我在这里将其包含在内,是为了在不引入Hook::LexWrap作为依赖项的情况下做到这一点,并且不会影响全局行为。

    {
        no strict 'refs';
        no warnings 'redefine';
        local *{'DateTime::today'} = sub {
            return DateTime->new(
                year  => 2012,
                month => 5,
                day   => 31
            );
        };
        say DateTime->today->ymd(); # 2012-05-31
    };
    
    say DateTime->today->ymd(); # today