Есть ли путь, или в коде или с аргументами JVM, для переопределения текущего времени, как представлено через System.currentTimeMillis
, кроме ручного изменения системы отмечают время прихода на работу хост-машина?
Немного фона:
У нас есть система, которая выполняет много бухгалтерских заданий, которые вращают большую часть их логики вокруг текущей даты (т.е. 1-й из месяца, 1-го из года, и т.д.)
К сожалению, много унаследованного кода вызывает функции такой как new Date()
или Calendar.getInstance()
, оба из которых в конечном счете раскритиковывают к System.currentTimeMillis
.
Для тестирования, прямо сейчас, мы застреваем с ручным обновлением системных часов для управления, во сколько и датируются, код думает, что тест запускается.
Таким образом, мой вопрос:
Есть ли способ переопределить то, что возвращается System.currentTimeMillis
? Например, чтобы сказать JVM автоматически добавлять или вычитать некоторое смещение прежде, чем возвратиться из того метода?
Заранее спасибо!
I настоятельно рекомендую вместо того, чтобы путаться с системными часами, кусать пулю и рефактор этого унаследованного кода, чтобы использовать сменные часы. В идеале это должно быть сделано с введением зависимостей, но даже если вы используете заменяемый одиночный блок, вы получите возможность проверки.
Это может быть почти автоматизировано с поиском и заменой версии одиночного блока:
Calendar.getInstance()
на Clock.getInstance(). getCalendarInstance()
.новую Date()
на Clock.getInstance().newDate()
System.currentTimeMillis()
на Clock. getInstance().currentTimeMillis()
(и т.д. по мере необходимости)
После того, как Вы сделали этот первый шаг, Вы можете заменить синглтон на DI немного за раз.
.Используйте Aspect-Oriented Programming (AOP, например AspectJ), чтобы переплетать класс System для возврата предопределенного значения, которое вы могли бы задать в ваших тестовых случаях.
Или переплетите классы приложений для перенаправления вызова на System.currentTimeMillis()
или на new Date()
на другой собственный класс утилиты.
Классы системы плетения (java.lang.*
), однако, немного сложнее, и вам, возможно, понадобится выполнить автономное плетение для rt.jar и использовать отдельную JDK/rt.jar для ваших тестов.
Это называется Двоичное плетение , и существуют также специальные инструменты для выполнения плетения системных классов и обхода некоторых проблем с этим (например, загрузка VM может не работать)
.Как сказал Джон Скит :
"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 кБ, поэтому она не должна ломать банк...
.На самом деле нет способа сделать это непосредственно в ВМ, но вы могли бы что-нибудь запрограммировать, чтобы установить системное время на тестовой машине. В большинстве (всех?) операционных систем есть команды командной строки для этого.
Powermock отлично работает. Просто использовал его для имитации System.currentTimeMillis ()
.