Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

manipulate current time in unit testing?

Tags:

java

time

junit

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.

like image 719
NA. Avatar asked Aug 02 '09 19:08

NA.


3 Answers

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.

like image 178
Yuval Adam Avatar answered Nov 01 '22 11:11

Yuval Adam


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.

like image 20
waxwing Avatar answered Nov 01 '22 10:11

waxwing


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.

like image 1
duffymo Avatar answered Nov 01 '22 10:11

duffymo