0

I have a function where I convert time in millis to a LocalDate object:

def convertToLocalDateTimeViaInstant(dateToConvert: java.util.Date): java.time.LocalDate =
    dateToConvert.toInstant.atZone(ZoneId.systemDefault).toLocalDate

And I have a unit test for this function as follows:

 "convertToLocalDateTimeViaInstant" should {
    "return the correct LocalDate instance" in new SAMLServiceTestEnv() {
      val timeInMillis: Long = 1349333576093L // Date is Thu Oct 04 2012 06:52:56 UTC in millis
      val someDate = new Date(timeInMillis) 
      val resultDate: LocalDate = samlServiceImpl.convertToLocalDateTimeViaInstant(someDate)
      
      resultDate.getYear mustEqual 2012
      resultDate.getMonth mustEqual java.time.Month.OCTOBER
      resultDate.getDayOfMonth mustEqual 4
    }
  }

When I run this test just by itself or the whole file, this test makes the correct assertions. The value 1349333576093L corresponds to Thu Oct 04 2012 06:52:56 UTC and Wed Oct 03 2012 23:52:56 PST (San Francisco time).

However, when I run ALL the unit tests in the project, I observe a failure in this test. The resultDate.getDayOfMonth mustEqual 4 assertion fails stating 4 is not equal to 3. I'm surprised to see this as the function clearly considers UTC time when run by itself but somehow observes local time when run all together? What am I doing wrong here?

Saturnian
  • 1,686
  • 6
  • 39
  • 65

1 Answers1

0

The standard practice is to not use LocalDate.now() directly. Like, at all. You have some Clock or Timer that is providing you with current time, and if you need to do any tests where time is important - you just stub this current time provider to fix time to some value. And you remove time-dependency from tests altogether. Any other approach is broken by design no matter how "pragmatic" you might want to see it.

As a matter of the fact Clock is a build-in in JDK 8: https://docs.oracle.com/javase/8/docs/api/java/time/Clock.html so you don't even have to introduce a new dependency.

Mateusz Kubuszok
  • 24,995
  • 4
  • 42
  • 64
  • I'm to follow what you're saying, except I can't find a way to not do it without `now()` - my code checks where a date is close to expiry and I would need `now()` to do that comparison. How would you suggest I do this? Even if I do use `Clock` to obtain the current date/time, how do I work with a custom `LocalDate` object? – Saturnian Nov 30 '20 at 17:26
  • [`clock.instant()`](https://docs.oracle.com/javase/8/docs/api/java/time/Clock.html#instant--) returns current `Instant` (`Instant.now()`) that can be [translated](https://stackoverflow.com/questions/52264768/how-to-convert-from-instant-to-localdate) to `LocalDate`. So you just can write an utility that takes `Clock` obtains `Instant` and converts it to `LocalDate` and you have a flexible `LocalDate.now()` replacement that can be mocked. – Mateusz Kubuszok Nov 30 '20 at 18:04