PHPUnit: Как смоделировать сегодняшнюю дату, не передавая ее в качестве аргумента? - PullRequest
12 голосов
/ 27 августа 2011

Я тестирую метод в своем классе, который проверяет некоторые даты.Проблема в том, что метод зависит от сегодняшней даты (которая меняется каждый день), что затрудняет его тестирование.Как я могу смоделировать сегодняшнюю дату, чтобы мои тесты по-прежнему проходили завтра?

Ответы [ 5 ]

8 голосов
/ 27 августа 2011

Я ничего не знаю о PHP, но как в Java, так и в C # я бы обозначил "часы" некоторого описания - не саму сегодняшнюю дату, а объект, который вы можете запросить для текущей даты / время. Затем в модульных тестах вы можете передать объект, который может дать любую желаемую дату, включая ту, которая жестко запрограммирована в тестах.

Это тоже работает в PHP?

6 голосов
/ 14 сентября 2011

Если вы заинтересованы в том, чтобы не указывать дату для сохранения внешнего интерфейса, то хорошим способом для этого является использование «шва» для предоставления даты:

class MyClass {
  public function toBeTested() {
    $theDate = $this->getDate();
    ...
  }

  protected function getDate() {
    return date();
  }
}

В общем случаеэтот класс просто работает нормально.Затем в модульном тестировании вместо тестирования MyClass вы расширяете MyClass внутренним классом, который переопределяет функцию getDate ():

class MyTest extends phpunittestcase (sorry, writing this freeform, syntax is not exact!!) {

  static $testDate;

  public function testToBeTested() {
    //set the date to be used
    MyTest::testDate = '1/2/2000';
    $classUnderTest = new MyClassWithDate();
    $this->assertEquals('expected', $classUnderTest->toBeTested());

  }

  //just pass back the expected date
  class MyClassWithDate extends MyClass {
    protected function getDate() {
      return MyTest::testDate;
    }
  }
}

В этом коде вы проверяете свое расширение реального класса,но ваше расширение переопределяет функцию шва (getDate ()) и возвращает дату, которую вы хотите использовать для этого конкретного теста.

Опять же, извините, если есть какие-то вопиющие синтаксические ошибки, это было написано от руки.

4 голосов
/ 27 августа 2011

Хотя ответ Джона - «правильный путь», другой вариант - использовать расширение runkit , чтобы временно заменить функции date() и / или time() функциями, возвращающими фиксированное значение для тест.

  1. Обязательно установите runkit.internal_override в php.ini, чтобы вы могли переименовывать встроенные функции.
  2. Переименуйте исходную функцию, используя runkit_function_rename.
  3. Переименуйте вашу макетную функцию с именем оригинала.
  4. Тест.
  5. Переименуй свой макет обратно.
  6. Переименуйте оригинал обратно.

Вот некоторый полностью непроверенный код, чтобы помочь с этим:

function mock_function($original, $mock) {
    runkit_function_rename($original, $original . '_original');
    runkit_function_rename($mock, $original);
}

function unmock_function($original, $mock) {
    runkit_function_rename($original, $mock);
    runkit_function_rename($original . '_original', $original);
}

Вы должны использовать их из методов setUp() и tearDown(), чтобы убедиться, что вы не мешаете другим следующим тестам.

3 голосов
/ 29 августа 2011

Я знаю, что вы не хотите передавать это в качестве аргумента. Но, может быть, вы можете переосмыслить это ...

При передаче в качестве параметра извне дата является не незначительной технической деталью, а важным функциональным правилом. Вам не нужно ничего из следующего?

  • Хотя текущая дата может использоваться в обычном порядке, правило может быть применимо к другой дате . Тогда ваш код будет более общим и будет работать в более позднем случае без изменений. Это случается со мной регулярно ...
  • Несколько кодов могут использовать текущую дату в алгоритме. Поскольку скорость компьютера не бесконечна, у нескольких будет разный момент ... Это логично с функциональной точки зрения? Или использование того же момента (например, момент, когда пользователь нажал кнопку «Огонь») будет более точным? Подумайте, как вы могли бы запросить это время в вашей базе данных позже, если они все разные в вашей базе данных, даже если они представляют одно и то же мгновение для вашего пользователя !
0 голосов
/ 27 декабря 2013

Я не мог дважды переименовать, как говорит Дэвид, поэтому я получил это как:

function mockDate()
{
    runkit_function_rename('date', 'test_date_override');
    runkit_function_add('date','$format=NULL,$timestamp=NULL,$locale=NULL', 'return DATEMOCK;');
}

function unmockDate()
{
    runkit_function_remove('date');
    runkit_function_rename('test_date_override', 'date');
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...