Tag Archives: JUnit

JUnit with new Date()

Writing unit tests for your code is great, but there are situations when it’s not possible without a little tweaking of the code itself. This is actually one good reason to write the test first.

For example, what do we do when confronted with the situation of writing a test for the following code:

public BigDecimal getInterestRate() {
  Date now = new Date();
  if (now.before(SWITCH_DATE)) {
    return oldInterestService.getInterestRate(ProductType.CREDIT);
  } else {
    return newInterestService.getInterestRate();
  }
}

The method is intended to get the interest rate from the old interest rate service unless we have passed a certain switch date. In this case, another service needs to be used to get the interest rate.

So how do we unit test this method? Well we can’t. It’s because of the infamous

Date now = new Date();

Writing a test for this will be unpredictable since every time we run it, the new Date() will return a different result.

Passing in the date as a param? Using a factory? Not so nice…

Normally we need to write 2 tests. One for the case when new Date() is before the SWITCH_DATE and assert the oldInterestService is used. Another for the case when new Date() is equal or after the SWITCH_DATE and assert the newInterestService is used.

To be able to quickly fix this, the Date can be passed in as a parameter to our method:

public BigDecimal getInterestRateForDate(Date date) {
  if (date.before(SWITCH_DATE)) {
    return oldInterestService.getInterestRate(ProductType.CREDIT);
  } else {
    return newInterestService.getInterestRate();
  }
}

Unfortunately this is not so great because we don’t completely encapsulate the implementation any more and actually allow the caller to control the resulted value. The caller may force using one service or another by passing a past or future date.

So we need some way of setting the date, but only from our test. Using the factory pattern may come in handy, but won’t be long until it would show its ugliness and weirdness. Why introduce complexity where things can be a lot more cleaner and easier?

Using a DateTimeService and mocks

If we have Dependency Injection at hand (like with EJB, Spring etc), and this is the case for most Java enterprise applications, things are about to get very neat. Why rely on the new Date() to tell us what day is today? Instead we can define a separate service for that. The big advantage is that we can later mock it.

public interface DateTimeService {
  Date getCurrentDate();
}

Then have it injected into the code and use it to get the current date.

public BigDecimal getInterestRate() {
  Date now = dateTimeService.getCurrentDate();
  ...
}

Of course, the default implementation of the DateTimeService interface would just return new Date(), but in our tests, we can mock it and have it return any date we need. Let’s assume we’re using EasyMock in our tests:

@Test
public void interestRateIsRetrievedFromNewInterestServiceAfterSwitchDate() {

  Date dateAfterSwitchDate = ...
  expect(dateTimeService.getCurrentDate()).andReturn(dateAfterSwitchDate);
  replay(dateTimeService);

  ...

}

Using EasyMock is just an example, but since the DateTimeService is an interface all mocking libraries will manage to work with it without any special tricks.

All this while the production code would use a simple implementation like:

public class DefaultDateTimeService implements DateTimeService {
  public Date getCurrentDate() {
    return new Date();
  }
}

Taking it further

Now a word from our unit test

Now a word from our unit test

This is a simple solution, but in the end it proves to be very powerful. This separation may be taken even further, especially in large enterprise systems. We all know how much applications rely on the system date. Trouble is that in large and heterogeneous deployments, the system date may vary slightly from system to system and sometimes it’s best the application retrieves its current date form a specialized system — like from a time server.

This can be easily accomplished by adding another implementation of our DateTimeService and have it connect to our time server instead of relying on system’s date. All other servers in the cluster, the DB etc. may do the same thing.

The only trick is to never use new Date() in code. Thankfully having your code unit tested will reveal all the dirty new Date()s before entering production an causing mayhem in, let’s say… credits department of a global bank.