ScalaTest: обрабатывать Instants как равные в течение одной миллисекунды

У меня есть класс case, который я сериализую в JSON, и тестовый пример, который проверяет, работает ли циклическое переключение.

Глубоко внутри корпуса класса находятся java.time.Instantс, которые я положил в JSON как их эпоху миллисекунд.

Оказывается, что Instant на самом деле имеет наносекундную точность, и это теряется при переводе, что делает тест неудачным, потому что временные метки немного сбиты.

Есть ли простой способ заставить Scalatest игнорировать разницу? Я просто хочу исправить тест, потеря точности полностью приемлема для приложения.

2 ответа

Решение

Мы используем Clock.instant, чтобы узнать текущее время вместо Instant.now, чтобы избежать этой проблемы. Таким образом, код для класса должен быть таким

class MyClass(clock: Clock) {
  def getResult(): Result = {
    Result(clock.instant)
  }
}

и на тесте мы высмеиваем clock.instant, чтобы гарантировать, что мы проверяем в одно и то же время.

class MyClassTest {
  val customTime = Instant.now
  val clock = mock[Clock]
  clock.instant() returns customTime

  // test
  val myClass = new MyClass(clock)
  val expectedResult = Result(customTime)
  myClass.getResult ==== expectedResult
}

Обрезать до миллисекунды перед сравнением

Я не уверен, что это поможет в вашей ситуации, но на всякий случай и для любого другого читающего вместе: правильный способ сравнения двух Instant объекты, учитывающие только миллисекунды и более грубые, должны усекать каждый с точностью до миллисекунды (здесь, в Java):

    Instant instant1 = Instant.parse("2018-12-14T08:25:54.232235133Z");
    Instant instant2 = Instant.parse("2018-12-14T08:25:54.232975217Z");
    if (instant1.truncatedTo(ChronoUnit.MILLIS).equals(instant2.truncatedTo(ChronoUnit.MILLIS))) {
        System.out.println("Equal to the millisecond");
    } else {
        System.out.println("Not equal to the millisecond");
    }

Выход:

Равно миллисекунде

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

Используйте часы, которые имеют только миллисекунду

Используя Clock для тестирования часто хорошая идея. Это может помочь вам написать воспроизводимые тесты. Вы можете легко иметь часы, которые считают только миллисекунды:

    Clock c = Clock.tickMillis(ZoneOffset.UTC);
    System.out.println(c.instant());
    System.out.println(Instant.now(c));

Вывод при запуске только сейчас:

2018-12-14T10:48:47.929Z
2018-12-14T10:48:47.945Z

Как видите, сгенерированный Instant объекты имеют только три десятичных знака в секундах, то есть с точностью до миллисекунды и ничего более точного. Когда вы используете только Clock для рисования Instants, не имеет значения, в какой часовой пояс вы переходите tickMillis,

Другие вопросы по тегам