Search code examples
javapowermockeasymock

Is there a way to return a new object each time with EasyMock return anyTimes()?


I'm working on a unit test for a class that relies heavily on Calendar. I'm trying to mock out all the calls so that I can basically insert my own specified system time into the class to do some date-time logic testing.

This is my first attempt:

Calendar fixedSystemCal = Calendar.getInstance();
fixedSystemCal.set(2021, Calendar.FEBRUARY, 22, 18, 0, 0);

PowerMock.mockStatic(Calendar.class);
EasyMock.expect(Calendar.getInstance()).andReturn(fixedSystemCal).anyTimes();
PowerMock.replay();

Unfortunately, after some poking around, I discovered that this doesn't work, because the calendar object is mutated inside the class. Since this mock returns the same calendar each time, this is a problem. For example:

Calendar firstCall = Calendar.getInstance(); //Feb 22
firstCall.add(Calendar.DATE, 5); //Feb 27

Calendar secondCall = Calendar.getInstance() // This is also Feb 27 now

Is there any way to get a different calendar object back each time (for an arbitrary number of calls)? The only solution I've found so far is just repeating it many times like this:

Calendar fixedSystemCal = Calendar.getInstance();
fixedSystemCal.set(2021, Calendar.FEBRUARY, 22, 18, 0, 0);

PowerMock.mockStatic(Calendar.class);
EasyMock.expect(Calendar.getInstance()).andReturn((Calendar) fixedSystemCal.clone()).andReturn((Calendar) fixedSystemCal.clone()).andReturn((Calendar) fixedSystemCal.clone());
PowerMock.replay();

I'm going to be replacing this code with Java time in the next step but I need a functioning unit test before I can make the change over.


Solution

  • You should be able to use andAnswer instead of andReturn to provide a lambda/IAnswer implementation that you can use to return a new instance. Something like:

    EasyMock.expect(Calendar.getInstance())
       .andAnswer(() -> (Calendar)fixedSystemCal.clone());