Тестирование блоков управления с условием на текущее время
Я пытаюсь настроить единичные тесты для некоторых классов утилиты в проекте, над которым я работаю, и один из классов (содержит информацию о лицензировании) имеет метод, который выполняет определенное определение на основе текущего времени.
то есть. лицензия содержит дату истечения срока действия, а строка лицензии проверяет эту дату, но фактическая логика, чтобы узнать, истек ли срок действия лицензии, основана на текущем времени.
public boolean isValid()
{
return isLicenseStringValid() && !isExpired();
}
public boolean isExpired()
{
Date expiry = getExpiryDate();
if( expiry == null ) {
return false;
}
Date now = new Date();
return now.after( expiry );
}
Итак, я не уверен, что делать, поскольку "новая функция Date()" не является статическим критерием.
- Должен ли я не пытаться проверить 'isValid' и просто проверить 'isLicenseStringValid()' и функцию getExpiryDate() отдельно?
- Я просто использую лицензионный ключ в тесте с сумасшедшим длительным сроком действия, чтобы у меня были переключения заданий к моменту истечения срока его действия?
- Я пытаюсь высмеять "новую дату()" для некоторого метода getCurrentTime(), чтобы я мог подделать, в какое время это сейчас?
Что обычно делают другие с тестами, которые являются условными по времени?
Ответы
Ответ 1
Определенно макет new Date()
.
Создайте интерфейс Clock
с помощью метода getCurrentTime()
или чего-то подобного. Таким образом, вы можете иметь FakeClock
для тестирования и SystemClock
, который использует System.currentTimeMillis()
или что-то еще.
Я делал это несколько раз - он работал очень хорошо. Это логично - эффективно вам требуется "служба текущего времени", поэтому ее следует вводить, как и любую другую зависимость.
Ответ 2
Я обычно вставляю поставщика даты в тестируемый код. Это также помогает, если вам нужно переключить соглашения или иначе "исправить" код тестирования времени.
Ответ 3
Используйте инъекцию зависимостей и введите TimeProvider
, который предоставляет метод getExpiryDate()
.
Ответ 4
Если вы считаете, что абстракция TimeProvider/Clock слишком перегружена перфекционистом (что вполне может быть так), рассмотрите это вместо
Сделать getCurrentType защищенным виртуальным, а затем создать testingProductionType decendant из ProductType, который содержит отправленный вами код. В этом типе переопределите метод getCurrentType(), чтобы вернуть некоторый детерминированный результат. В unit test вместо этого создайте экземпляр этого TestingProductionType.
Виола, зависимость текущего времени теперь удаляется из ваших модульных тестов. Единственный производственный код, который теперь не тестируется на единицу, - это метод с одной строкой, возвращающей новую Date(). Я мог бы жить с этим.
Ответ 5
Если вы можете проверить Mole на http://research.microsoft.com/en-us/projects/pex/
Moles allows to replace any .NET method with a delegate
Просто используйте его, чтобы заменить Date и вернуть его, что вам нужно. Тогда вам не нужно ничего сумасшедшего.
-Raul
Ответ 6
Возможны все три подхода:
- не проверяйте: ленивый путь человека
- используйте лицензию, срок действия которой не истечет до тех пор, пока вы не оставите работу: закройте мой путь.
- использовать макет для текущей даты, например, TimeProvider: перфекционистский способ
Я хотел бы включить: я бы добавил текущую дату в качестве параметра к методу isExpired и метод isValid. Для вашего живого производственного кода добавьте простое isValid()
no-arg override, которое вызывает isValid(new Date())
. В вашем тестовом коде используется версия, которая принимает текущую дату в качестве параметра.