How to resolve side effect rising from LocalDate in tests (scala)?

312 Views Asked by At

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?

1

There are 1 best solutions below

2
On

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.