Как переопределить / контролировать способ, которым JVM получает системную дату? - PullRequest
4 голосов
/ 31 марта 2010

Как вы макете / обманываете JVM, чтобы получить дату, отличную от текущей системной даты?У меня есть набор тестов в JUnit, который я не хочу менять, но вместо этого я хочу изменить настройку, чтобы при получении JVM даты получала дату, которую я хочу.

Вы сделали что-то подобноераньше?

Спасибо.

Ответы [ 4 ]

5 голосов
/ 01 апреля 2010

Есть несколько способов сделать это:

  • если вы можете переписать код - как уже упоминалось в некоторых других ответах, в основном вам нужен настраиваемый NowProvider, DateFactory или другая стратегия (мне нравится injectable NowProvider.now (), как замена для System.currentTimeMillis)

  • Powermock и некоторые другие наборы инструментов позволяют использовать приемы ClassLoader для переопределения статических методов, даже системных методов

1 голос
/ 31 марта 2010

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

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

Однако, если вы не можете изменить код, который вы тестируете, у вас может не быть другого пути. Тогда возникает вопрос: вас интересует только дата или полная отметка времени? Последний случай звучит для меня довольно безнадежно (каким-либо иным способом, кроме описанного выше макета интерфейса), так как я предполагаю, что простого сброса даты перед запуском тестов недостаточно - вам нужно фиксированный момент времени, чтобы его можно было вернуть по всему устройству. тесты. Может быть, ваши тесты выполняются достаточно быстро, чтобы закончить до того, как тикают часы, а может и нет - возможно, они пройдут прямо сейчас, а затем начнут случайно проваливаться через некоторое время после добавления следующего теста: - (

Если вам нужна только дата, вы можете попробовать изменить дату в методе @BeforeClass, а затем сбросить ее в @AfterClass, хотя это и брутто.

1 голос
/ 31 марта 2010

У вас может быть интерфейс DateFactory с двумя реализациями, одна из которых всегда возвращает new Date() (это будет использоваться в производстве), и фиктивный объект, который возвращает Date объекты, которые больше подходят для ваших модульных тестов.

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

0 голосов
/ 06 августа 2012

Вы можете написать TestRule для него. Примерно так может работать:

import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class FixedDateTimeRule implements TestRule {

   private final DateTime fixedDate;

   public FixedDateTimeRule(DateTime fixedDate) {
      this.fixedDate = fixedDate;
   }

   /*
    * (non-Javadoc)
    * 
    * @see org.junit.rules.TestRule#apply(org.junit.runners.model.Statement, org.junit.runner.Description)
    */
   @Override
   public Statement apply(final Statement base, Description description) {
      return new Statement() {

         @Override
         public void evaluate() throws Throwable {
            DateTimeUtils.setCurrentMillisFixed(fixedDate.getMillis());
            try {
               base.evaluate();
            } finally {
               DateTimeUtils.setCurrentMillisSystem();
            }
         }
      };
   }

}

@Rule
public FixedDateTimeRule fixedDateTime = new FixedDateTimeRule(new DateTime(...))
@Test
public void someKindOfTestThatNeedsAFixedDateTime() { ... }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...