tags:

views:

204

answers:

3

Is there any way to manipulate the current time in a jUnit 4.5 test? I have the following method which I'd like to have a unit test for

public String getLastWeek() {
  GregorianCalendar c = new GregorianCalendar(TimeZone.getTimeZone("Europe/Stockholm"));
  c.setFirstDayOfWeek(GregorianCalendar.MONDAY);
  c.add(GregorianCalendar.WEEK_OF_YEAR, -1);
  return c.get(GregorianCalendar.YEAR) + " " + c.get(GregorianCalendar.WEEK_OF_YEAR);
}

One way to make it easier to test is to split it into two methods

public String getLastWeek() {
  GregorianCalendar c = new GregorianCalendar(TimeZone.getTimeZone("Europe/Stockholm"));
  return getLastWeekFor(c);
}

public String getLastWeekFor(GregorianCalander c) {
  c.setFirstDayOfWeek(GregorianCalendar.MONDAY);
  c.add(GregorianCalendar.WEEK_OF_YEAR, -1);
  return c.get(GregorianCalendar.YEAR) + " " + c.get(GregorianCalendar.WEEK_OF_YEAR);
}

That lets me test the week subtraction logic, but leaves getLastWeek untested and I prefer to have just one method for this.

+4  A: 

You have no real way of manipulating system time.

Actually, you refactored the method rather nicely in order to make it testable. I would keep it at that.

Yuval A
+2  A: 

I can see two paths here.

Either, create a DateUtils factory class, which encapsulates the construction of Calendar and Date instances. Then you can swap this for a controllable factory. I.e., you have a second implementation of DateUtils that also exposes a setCurrentTime method, and will then explicitly return Calendar instances set to that date.

Or, you can use JMockit to actually "redefine" your call of new GregorianCalendar so instead a mock instance is returned. I have not done this myself, but there is a description here.

Your option, breaking the method into two methods, is also a perfectly valid option. I think that it is what most people do - including myself: but the truth is that it does hurt your design, especially if the class is exposed to other code.

waxwing
The first two suggestions, while are perfectly valid and even heavily used in other situations, feel a bit of an overkill to OP's needs.
Yuval A
+1  A: 

Looks like you're trying to recreate what JODA Time does. I'll cite it in case you aren't aware. You can make the trade-off between reinventing the wheel and adding a dependency.

duffymo
Actully I found JODA earlier today and realised that was what I actully wanted to be using. How would a testable JODA version look? Or should I simply assume that JODA is working correct as it should have it's own tests?
NA
Check the JODA source out and see if it's unit tested. I'm betting that it is. Usually I assume a 3rd party library is tested until it gives me a reason to believe otherwise. At worst, they have a bigger user base than you do. Lots of people banging on code is a good way to find and fix lots of errors.
duffymo