简体   繁体   中英

Mocking Calendar.getInstance static method multiple times in a method

I am currently using JMockito/PowerMock so that I can mock the return value of a static method, in this case, Calendar.getInstance(). My issue is very similar to this, but not quite: PowerMocking static does not return expected object

I have also checked various other similar topics but none of them quite falls into my context. Currently, I have a code that like this:

Calendar cal = Calendar.getInstance();
//modifies this instance
.....
.....
//then there is another call:
cal2 = Calendar.getInstance();
....
....

What the logic does is not important here. When I have tried testing this block of method, I have expectation like so:

Calendar myOwn = //whatever
when(Calendar.getInstance()).thenReturn(myOwn);

So during test what happens testing is that in the first call of Calendar.getInstance() it manages to successfully get myOwn object which is what I expect. And obviously, the method then does some modification to this object.

However , while debugging, when the next call Calendar.getInstance() happens later, the variable cal2 seems to get the modified version of myOwn object from before. I would have thought that it would get the original myOwn calendar object but it doesn't.

I have also tried rebuilding the expectation to this (because there is a total of two getInstance() calls, at least in this method):

when(Calendar.getInstance()).thenReturn(myOwn).theReturn(myOwn);

but no luck. Then I thought whether this was an issue of variable getting passed by reference due to it being static however, the following output is valid and perfectly logical too as I tested it in isolation.

Calendar cal = Calendar.getInstance();
System.out.println(cal.getTime()); //prints current date object (as expected)

cal.set(Calendar.YEAR, 2017);
System.out.println(cal.getTime()); //prints modified timestamp of 2017 (as expected)

//new instance
Calendar cal2 = Calendar.getInstance();
System.out.println(cal2.getTime()); //still prints current date object (as expected)

I can easily fix my test if I clone the second instance of calendar object in code from previous before it gets modified. But this involve modifying existing source code which I can't as it's quite a legacy code.

So what have I done wrong in my unit test with this static method? I have also tried testing with JMockit and still get the same issue. Pretty sure it's something obvious but cannot figure it out. Thank you for your time.

That's because myOwn is the same instance. The thenReturn code is only run once at the start of your test. You've created only the one Calendar object, and Mockito is simply returning it twice. So if it's modified the first time getInstance is called, that modified object will be returned the second time it's called.

Try instead:

Calendar myOwn = //whatever
Calendar myOwnSecond = //whatever - new instance though, not the same as myOwn!!
when(Calendar.getInstance()).thenReturn(myOwn).thenReturn(myOwnSecond);

If you want to return a new calendar instance each time (so for times when you want x number of Calendar instances), and you don't need to hold on to the calendar instance for your test, you'll want to use thenAnswer . Look here for details. Or just use:

when(Calendar.getInstance()).thenAnswer((invocation)->new MyCalendar());

or Java 7

when(Calendar.getInstance())
    .thenAnswer(new Answer<Calendar>() {
        Calendar answer(InvocationOnMock invocation) {
            return // however you're instantiating it
    }
});    

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM