In my code I have something like this:
private void doSomething() {
Calendar today = Calendar.getInstance();
....
}
How can I \"mock\
Write a class called DateHelper
with a method getCalendar
that returns Calendar.getInstance()
. Refactor the class that you're testing so that it has a member variable of type DateHelper
, and a constructor that injects that member variable. Use that constructor in your test, to inject a mock of DateHelper
, in which getCalendar
has been stubbed to return some known date.
As far as I see it you have three sensible options:
Inject the Calendar
instance in whatever method/class you set that day in.
private void method(final Calendar cal)
{
Date today = cal.getTime();
}
Use JodaTime instead of Calendar
. This is less an option and more a case of a suggestion as JodaTime will make your life a lot easier. You will still need to inject this time in to the method.
DateTime dt = new DateTime();
Date jdkDate = dt.toDate();
Wrap Calendar
inside some interface that allows you to fetch the time. You then just mock that interface and get it to return a constant Date
.
Date today = calendarInterfaceInstance.getCurrentDate()
Using Mockito and PowerMockito:
Calendar endOfMarch = Calendar.getInstance();
endOfMarch.set(2011, Calendar.MARCH, 27);
PowerMockito.mockStatic(Calendar.class);
Mockito.when(Calendar.getInstance()).thenReturn(endOfMarch);
Refer to the link for the complete code.
You can mockit using JMockit. Here you can see how you can do it: Mock Java Calendar - JMockit vs Mockito.
You can mock it using PowerMock in combination with Mockito:
On top of your class:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassThatCallsTheCalendar.class})
The key to success is that you have to put the class where you use Calendar in PrepareForTest instead of Calendar itself because it is a system class. (I personally had to search a lot before I found this)
Then the mocking itself:
mockStatic(Calendar.class);
when(Calendar.getInstance()).thenReturn(calendar);
Don't mock it - instead introduce a method you can mock that gets dates. Something like this:
interface Utility {
Date getDate();
}
Utilities implements Utility {
public Date getDate() {
return Calendar.getInstance().getTime();
}
}
Then you can inject this into your class or just use a helper class with a bunch of static methods with a load method for the interface:
public class AppUtil {
private static Utility util = new Utilities();
public static void load(Utility newUtil) {
this.util = newUtil;
}
public static Date getDate() {
return util.getDate();
}
}
Then in your application code:
private void doSomething() {
Date today = AppUtil.getDate();
....
}
You can then just load a mock interface in your test methods.
@Test
public void shouldDoSomethingUseful() {
Utility mockUtility = // .. create mock here
AppUtil.load(mockUtility);
// .. set up your expectations
// exercise the functionality
classUnderTest.doSomethingViaAPI();
// ... maybe assert something
}
See also Should you only mock types you own? and Test smell - everything is mocked