Как я могу протестировать Perl-приложения, используя изменение системного времени? - PullRequest
2 голосов
/ 12 сентября 2009

У меня есть веб-приложение, на котором я хочу запустить некоторые системные тесты, и для этого мне нужно будет изменить системное время. Приложение полностью использовало DateTime.

Кто-нибудь получил какие-либо рекомендации о том, как изменить время, которое DateTime-> теперь сообщает? Единственное, что приходит на ум - это подкласс DateTime и возиться со всеми строками «использования», но это кажется довольно агрессивным.

Примечание к ответам:

Все три будут работать нормально, но я выбрал Hook :: LexWrap one, потому что (а) я хочу перемещать часы, а не немного их покачивать (что является большей целью того, что Time :: Издеваться и делать друзья); (б) я последовательно использую DateTime, и я рад, что появляются ошибки, если я случайно не использовал его; и (c) Hook :: LexWrap просто более элегантен, чем хак в таблице символов, несмотря на то, что он делает то же самое. (Кроме того, оказывается, что это какой-то модуль, который я уже установил, поэтому мне даже не пришлось его CPAN ...)

Ответы [ 4 ]

11 голосов
/ 12 сентября 2009

Вместо того, чтобы использовать высокоуровневый подход и конкретизировать DateTime, вам может потребоваться изучить модули Test :: MockTime и Time :: Mock , которые переопределяют низкоуровневые функции, которые DateTime и т. д. используют, и (если повезет) будут делать правильные вещи с любым чувствительным ко времени кодом. Мне кажется, это более надежный способ тестирования.

4 голосов
/ 12 сентября 2009

Я думаю, что 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 извне файла, содержащего этот код.

Вы можете настроить $offset в любое время, если хотите изменить представление DateTime о текущем времени во время выполнения.

Расчет $offset, вероятно, должен быть более сложным, чем показано выше. Например, чтобы установить «текущее время» в абсолютное время:

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 заключается в том, что такие вещи, как изменения летнего времени, приводят к тому, что время прыгает в неправильное псевдо-время.

1 голос
/ 31 мая 2012

При проектировании нового класса с учетом тестируемости идеальным решением является возможность добавления новых объектов даты.

Однако для существующего кода, использующего 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
1 голос
/ 12 сентября 2009

Вы можете использовать внедрение кода через 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";
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...