Intereting Posts
Regexp для определения времени вызова по ссылкам в исходном коде PHP Как передать параметры в jquery Laravel Class Socialite не найден Как получить адрес электронной почты при аутентификации пользователя с помощью Google Oauth2 и people.me PHP сгенерированный контент внутри скрипта Javascript PHP переписывает включенный файл – это допустимый скрипт? Подтвердить электронную почту в php Facebook Connect, как разрешить пользователям находить и приглашать друзей на ваш сайт? тайм-аут сеанса из-за неактивности Как создать вложенный список из массива PHP для выпадающего списка? Примечание. Неопределенная переменная: _SESSION в строке "" в строке 9 Как показать большие числа на К (означает килограмм)? AWS SDK PHP Class 'Aws \ DynamoDb \ Model \ BatchRequest \ WriteRequestBatch' не найден Как заменить все прописные буквы тире и строчными буквами регулярным выражением? Получение последнего МБ файла с помощью cURL

Могу ли я «Mock» время в PHPUnit?

… не зная, является ли «макет» правильным словом.

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

В какой-то момент мне также нужно попробовать добавить что-то в эту историю и проверить, что порог теперь изменен (и, очевидно, исправлен).

Проблема, с которой я сталкиваюсь, заключается в том, что часть кода, который я тестирую, использует вызовы во времени (), и поэтому мне очень трудно точно узнать, какое пороговое время должно быть, в зависимости от того, m не совсем точно, когда будет вызвана функция time ().

Поэтому мой вопрос в основном таков: есть ли способ для меня «переопределить» вызов time () или каким-то образом «измотать» время, чтобы мои тесты работали в «известное время»?

Или мне просто нужно признать тот факт, что мне придется что-то делать в коде, который я тестирую, чтобы каким-то образом позволить мне заставить его использовать определенное время, если это необходимо?

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

Редактировать: часть моей проблемы также заключается в том, что время, которое произошло в истории, влияет на порог. Вот пример части моей проблемы …

Представьте, что у вас есть банан, и вы пытаетесь разобраться, когда его нужно съесть. Предположим, что срок его действия истекает в течение 3 дней, если только он не был распылен каким-либо химическим веществом, и в этом случае мы добавляем 4 дня до истечения срока действия с момента применения спрея . Затем мы можем добавить еще 3 месяца, заморозив его, но если он был заморожен, у нас есть только один день, чтобы использовать его после его оттаивания.

Все эти правила продиктованы историческими таймингами. Я согласен с тем, что я мог бы использовать предложение Доминика по тестированию в течение нескольких секунд, но что из моих исторических данных? Должен ли я просто «создавать» это на лету?

Поскольку вы можете или не можете сказать, я все еще пытаюсь понять всю концепцию «тестирования»;)

Недавно я придумал другое решение, которое отлично, если вы используете пространства имен PHP 5.3. Вы можете реализовать новую функцию time () внутри вашего текущего пространства имен и создать общий ресурс, в котором вы устанавливаете возвращаемое значение в своих тестах. Тогда любой неквалифицированный вызов функции time () будет использовать вашу новую функцию.

Для дальнейшего чтения я подробно описал это в своем блоге

Отказ от ответственности: я написал эту библиотеку.

Вы можете высмеивать время для тестирования с помощью часов от ouzo-goodies .

В коде используйте просто:

 $time = Clock::now(); 

Затем в тестах:

 Clock::freeze('2014-01-07 12:34'); $result = Class::getCurrDate(); $this->assertEquals('2014-01-07', $result); 

Лично я продолжаю использовать time () в проверенных функциях / методах. В тестовом коде просто убедитесь, что вы не проверяете равенство по времени (), но просто для разницы во времени менее 1 или 2 (в зависимости от того, сколько времени функция выполняет для выполнения)

Мне пришлось моделировать конкретный запрос в будущем и прошлую дату в самом приложении (не в Unit Tests). Следовательно, все вызовы \ DateTime :: now () должны возвращать дату, установленную ранее в приложении.

Я решил пойти с этой библиотекой https://github.com/rezzza/TimeTraveler , так как я могу издеваться над датами без изменения всех кодов.

 \Rezzza\TimeTraveler::enable(); \Rezzza\TimeTraveler::moveTo('2011-06-10 11:00:00'); var_dump(new \DateTime()); // 2011-06-10 11:00:00 var_dump(new \DateTime('+2 hours')); // 2011-06-10 13:00:00 

В большинстве случаев это будет сделано. Он имеет ряд преимуществ:

  • вам не нужно издеваться над чем-нибудь
  • вам не нужны внешние плагины
  • вы можете использовать любую функцию времени, а не только время (), но и объекты DateTime
  • вам не нужно использовать пространства имен.

Он использует phpunit, но вы можете добавить его в любую другую структуру тестирования, вам просто нужна функция, которая работает как assertContains () из phpunit.

1) Добавьте функцию ниже в ваш тестовый класс или загрузочный файл. Допуск по умолчанию для времени составляет 2 секунды. Вы можете изменить его, передав третий аргумент assertTimeEquals или изменив функцию args.

 private function assertTimeEquals($testedTime, $shouldBeTime, $timeTolerance = 2) { $toleranceRange = range($shouldBeTime, $shouldBeTime+$timeTolerance); return $this->assertContains($testedTime, $toleranceRange); } 

2) Пример тестирования:

 public function testGetLastLogDateInSecondsAgo() { // given $date = new DateTime(); $date->modify('-189 seconds'); // when $this->setLastLogDate($date); // then $this->assertTimeEquals(189, $this->userData->getLastLogDateInSecondsAgo()); } 

assertTimeEquals () проверяет, содержит ли массив (189, 190, 191) 189.

Этот тест должен быть передан для правильной рабочей функции. IF, выполняющий тестовую функцию, занимает менее 2 секунд.

Это не идеально и суперточно, но это очень просто, и во многих случаях достаточно проверить, что вы хотите проверить.

Самое простое решение – переопределить функцию PHP time () и заменить ее собственной версией. Однако вы не можете легко заменить встроенные функции PHP ( см. Здесь ).

Короче говоря, единственный способ – абстрагировать вызов time () на определенный класс / функцию, которая вернет время, необходимое для тестирования.

Кроме того, вы можете запустить тестовую систему (операционную систему) на виртуальной машине и изменить время всего виртуального компьютера.

Вы можете переопределить функцию time () php с помощью расширения runkit. Убедитесь, что вы установили runkit.internal_overide в положение On

Использование расширения [runkit] [1]:

 define('MOCK_DATE', '2014-01-08'); define('MOCK_TIME', '17:30:00'); define('MOCK_DATETIME', MOCK_DATE.' '.MOCK_TIME); private function mockDate() { runkit_function_rename('date', 'date_real'); runkit_function_add('date','$format="Ymd H:i:s", $timestamp=NULL', '$ts = $timestamp ? $timestamp : strtotime(MOCK_DATETIME); return date_real($format, $ts);'); } private function unmockDate() { runkit_function_remove('date'); runkit_function_rename('date_real', 'date'); } 

Вы можете даже проверить макет, как это:

 public function testMockDate() { $this->mockDate(); $this->assertEquals(MOCK_DATE, date('Ym-d')); $this->assertEquals(MOCK_TIME, date('H:i:s')); $this->assertEquals(MOCK_DATETIME, date()); $this->unmockDate(); } 

Вот дополнение к публикации Fab. Я использовал переопределение пространства имен с использованием eval. Таким образом, я могу просто запустить его для тестирования, а не для остальной части моего кода. Я запускаю функцию, похожую на:

 function timeOverrides($namespaces = array()) { $returnTime = time(); foreach ($namespaces as $namespace) { eval("namespace $namespace; function time() { return $returnTime; }"); } } 

затем перейдите в timeOverrides(array(...)) в тестовой настройке, чтобы мои тесты только отслеживали, timeOverrides(array(...)) время пространства имен ().

Для тех из вас, кто работает с symfony (> = 2,8): PHPUnit Bridge от Symfony включает функцию ClockMock, которая переопределяет встроенные методы, time , microtime , sleep и sleep .

См .: http://symfony.com/doc/2.8/components/phpunit_bridge.html#clock-mocking