Java System.currentTimeMillis переопределения для тестирования времени чувствительный код

Есть ли путь, или в коде или с аргументами JVM, для переопределения текущего времени, как представлено через System.currentTimeMillis, кроме ручного изменения системы отмечают время прихода на работу хост-машина?

Немного фона:

У нас есть система, которая выполняет много бухгалтерских заданий, которые вращают большую часть их логики вокруг текущей даты (т.е. 1-й из месяца, 1-го из года, и т.д.)

К сожалению, много унаследованного кода вызывает функции такой как new Date() или Calendar.getInstance(), оба из которых в конечном счете раскритиковывают к System.currentTimeMillis.

Для тестирования, прямо сейчас, мы застреваем с ручным обновлением системных часов для управления, во сколько и датируются, код думает, что тест запускается.

Таким образом, мой вопрос:

Есть ли способ переопределить то, что возвращается System.currentTimeMillis? Например, чтобы сказать JVM автоматически добавлять или вычитать некоторое смещение прежде, чем возвратиться из того метода?

Заранее спасибо!

117
задан Ashish Kumar 6 December 2017 в 08:24
поделиться

5 ответов

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

Это может быть почти автоматизировано с поиском и заменой версии одиночного блока:

  • Замените Calendar.getInstance() на Clock.getInstance(). getCalendarInstance().
  • Заменить новую Date() на Clock.getInstance().newDate()
  • Заменить System.currentTimeMillis() на Clock. getInstance().currentTimeMillis()

(и т.д. по мере необходимости)

После того, как Вы сделали этот первый шаг, Вы можете заменить синглтон на DI немного за раз.

.
109
ответ дан 24 November 2019 в 02:06
поделиться

Используйте Aspect-Oriented Programming (AOP, например AspectJ), чтобы переплетать класс System для возврата предопределенного значения, которое вы могли бы задать в ваших тестовых случаях.

Или переплетите классы приложений для перенаправления вызова на System.currentTimeMillis() или на new Date() на другой собственный класс утилиты.

Классы системы плетения (java.lang.*), однако, немного сложнее, и вам, возможно, понадобится выполнить автономное плетение для rt.jar и использовать отдельную JDK/rt.jar для ваших тестов.

Это называется Двоичное плетение , и существуют также специальные инструменты для выполнения плетения системных классов и обхода некоторых проблем с этим (например, загрузка VM может не работать)

.
6
ответ дан 24 November 2019 в 02:06
поделиться

Как сказал Джон Скит :

"Use Joda Time" почти всегда является лучшим ответом на любой вопрос, связанный с "как мне достичь X с помощью java.util.Date/Calendar?"

Так что вот (предположим, что вы только что заменили все ваши новые Date() на новые DateTime(). toDate())

//Change to specific time
DateTimeUtils.setCurrentMillisFixed(millis);
//or set the clock to be a difference from system time
DateTimeUtils.setCurrentMillisOffset(millis);
//Reset to system time
DateTimeUtils.setCurrentMillisSystem();

Если Вы хотите импортировать библиотеку, имеющую интерфейс (см. комментарий Джона ниже), Вы можете просто использовать Prevayler's Clock, который обеспечит реализацию, а также стандартный интерфейс. Полная банка составляет всего 96 кБ, поэтому она не должна ломать банк...

.
42
ответ дан 24 November 2019 в 02:06
поделиться

На самом деле нет способа сделать это непосредственно в ВМ, но вы могли бы что-нибудь запрограммировать, чтобы установить системное время на тестовой машине. В большинстве (всех?) операционных систем есть команды командной строки для этого.

3
ответ дан 24 November 2019 в 02:06
поделиться

Powermock отлично работает. Просто использовал его для имитации System.currentTimeMillis () .

7
ответ дан 24 November 2019 в 02:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: