Есть ли способ имитировать временную метку LocalDateTime с использованием спецификаций - PullRequest
0 голосов
/ 05 мая 2020

Я предположительно участвую в интеграционных тестах библиотеки, которая использует specs с базовой реализацией, написанной на Scala. Тестирование больше связано с потоком событий, протекающим с некоторым атрибутом timestamp.

Следующая заглушка является частью фактической реализации

private def eligibleForRecentPost(optionalPost: Option[SearchEntity]): Boolean = {
    optionalSearch.map(search => search.timestamp)
      .exists(searchTime => searchTime >= LocalDateTime.now()
        .minusDays(recencyDurationInDays).atZone(ZoneId.systemDefault).toInstant.toEpochMilli)
}

Теперь код, который я хотел бы search for может выглядеть примерно так:

// just a mock
when(LocalDateTime.now().minusDays(any)
    .atZone(ZoneId.systemDefault).toInstant.toEpochMilli)
    .thenReturn(1579625874972)

Обратите внимание, я знаю, что search.timestamp в тесте может быть обновлен, но это потребует обновления событий после каждого recencyDurationInDays !!

Но есть ли лучший и надежный способ сделать это в specs2 и / или scala?

Edit : я должен упомянуть, что я не с нетерпением жду изменения реализации, чтобы LocalDateTime был переопределен / заключен в другой класс.

1 Ответ

5 голосов
/ 05 мая 2020

Существуют такие инструменты, как powermock , которые позволяют такие вещи. Но они являются последним решением, если вам нужно имитировать что-то в коде, над которым вы не можете контролировать.

Обычно вместо этого вы должны сделать что-то вроде:

trait Clock {

  def now(): LocalDateTime  
}

class DefaultClock extends Clock {

  def now(): LocalDateTime = LocalDateTime.now()
}

, а затем ввести Clock экземпляр в код, который его использует.

Вместо имитации метода c вы можете просто передать экземпляр, который делает все, что вы хотите:

val simulatedNow = ... // calculate the right date for now
val clock = new Clock {
  def now() = simulatedNow
}
// inject clock
// run code and check assertion
...