2010-08-11 1 views
14

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

т. Е. Лицензия содержит дату истечения срока действия, а строка лицензии проверяет эту дату, но фактическая логика, чтобы узнать, истек ли срок действия лицензии, основана на текущем времени.

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()», что не является статическим критерий.

  1. Должен ли я не тестировать 'isValid' и просто проверить 'isLicenseStringValid()' и функцию getExpiryDate() 'отдельно?
  2. Я просто использую лицензионный ключ в тесте с сумасшедшим длительным сроком действия, чтобы у меня были переключения заданий к моменту истечения срока его действия?
  3. Я пытаюсь высмеять «новую дату()» для некоторого метода getCurrentTime(), чтобы я мог подделать, в какое время это сейчас?

Что обычно делают другие люди с тестами, которые являются условными по времени?

+0

BTW, я вижу проблему в коде, кроме даты логики: если (экспирации == NULL) { возвращение ложным; } Я не думаю, что вы должны возвращать 'false' в' isExpired() ', если дата истечения равна null. Для получения дополнительной информации прочитайте - https://www.owasp.org/index.php/Fail_securely – Garbage

+0

Это объект лицензии, который имеет два возможных режима: 1. вечный без истечения срока действия (отсюда выше) 2. временный с датой истечения срока действия , так что это правильно, если нет установленной даты истечения срока действия, срок ее действия истек. –

ответ

23

Определенно макет new Date().

Создайте интерфейс Clock с помощью метода getCurrentTime() или чего-нибудь подобного. Таким образом, вы можете получить FakeClock для тестирования и SystemClock, который использует System.currentTimeMillis() или что-то еще.

Я делал это несколько раз - он работал очень хорошо. Это тоже логично - эффективно вам требуется «сервис текущего времени», поэтому его следует вводить, как и любую другую зависимость.

+0

Спасибо, он чувствует себя немного странно, используя DI для вещей, которые чувствуют себя частью самого языка, но похоже, что это сработает. –

5

Я обычно вставляю поставщика даты в тестируемый код. Это также помогает, если вам нужно переключить соглашения или иначе «исправить» код тестирования времени.

2

Используйте инъекцию зависимости и введите TimeProvider, который предоставляет метод getExpiryDate().

1

Все три подхода:

  1. не тест: путь ленивого человека
  2. использовать лицензию, не истекает в течение веков, пока вы не оставили работу: покрыть мою задницу путь
  3. использовать макет для текущей даты, такие как TimeProvider: перфекционист путь

Я бы пойти на comprimise: Я хотел бы добавить текущую дату в качестве параметра метода isExpired и IsValid метод. Для вашего живого кода производства добавьте простой isValid() no-arg override, который вызывает isValid(new Date()). В вашем тестовом коде используется версия, которая принимает текущую дату в качестве параметра.

+0

Этот вариант мне больше всего нравится. Если язык поддерживает аргументы по умолчанию, это делает его немного проще. – elias

2

Если вы чувствуете TimeProvider/Часы абстракция слишком борт перфекционист (что вполне может быть), рассмотрим это вместо

Сделать getCurrentType защищенный виртуальный, а затем создать TestingProductionType-потомок в ProductionType, который содержит код вы отправили.В этом типе переопределите метод getCurrentType(), чтобы вернуть некоторый детерминированный результат. В своем модульном тесте вместо этого создайте экземпляр этого TestingProductionType.

Виола, зависимость текущего времени теперь удаляется из ваших модульных тестов. Единственный производственный код, который теперь не тестируется на единицу, - это метод с одной строкой, возвращающей новую Date(). Я мог бы жить с этим.

2

Если вы можете проверить Mole по телефону http://research.microsoft.com/en-us/projects/pex/ Moles allows to replace any .NET method with a delegate Просто используйте его, чтобы заменить дату и вернуть ее, что вам нужно. Тогда вам не нужно ничего сумасшедшего.

-Raul

Смежные вопросы