In my code I have something like this:
private void doSomething() { Calendar today = Calendar.getInstance(); .... }
How can I "mock" it in my junit test to return a specific date?
In my code I have something like this:
private void doSomething() { Calendar today = Calendar.getInstance(); .... }
How can I "mock" it in my junit test to return a specific 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()
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
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);
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.
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.
You can mockit using JMockit. Here you can see how you can do it: Mock Java Calendar - JMockit vs Mockito.
For those who follows MVP pattern mocking Calendar is a piece of cake:
In a Presenter create a method which returns calendar instance:
public Calendar getCurrentTime() { return Calendar.getInstance(); }
In your view (Activity, Fragment etc) you access the calendar with help of presenter:
Calendar calendar = mPresenter.getCurrentTime(); // do whatever you want
In your tests you do:
// create a dummy calendar Calendar mockCalendar = ... // You've already mocked your Presenter, haven't you? when(mMockPresenter.getCurrentTime()).thenReturn(mockCalendar); // here you are!