Search code examples
javatestingjunitmockitopowermockito

PowerMockito: can not mock Calendar.getInstance


How looks my code

@RunWith(PowerMockRunner.class)
@PrepareForTest({Calendar.class})
public class TestSomething {

  @Test
  public void mockCalendar() {
     Calendar calendar = Calendar.getInstance();
     PowerMockito.mockStatic(Calendar.class);
     //a few attempts here
     PowerMockito.when(Calendar.getInstance()).thenReturn(calendar);
     // or
     BDDMockito.when(Calendar.getInstance()).thenReturn(calendar);
     //or 
     Mockito.when(Calendar.getInstance()).thenReturn(calendar);
     //or
     BDDMockito.given(Calendar.getInstance()).willReturn(calendar);
}
}

But in every case, Calendar call real method .getInstance(). In previous cases, everything worked fine with BDDMockito, but now i have a problem


Solution

  • Assuming that your actual is the one posted in the original question, I think you are using PowerMock wrong.

    Suppose that I have the following class which has a method like the one, hard coupling to Calendar which I need to mock its creation (via the Calendar#getInstance method).

    public class SomeClass {
    
        public Calendar createInstance() {
            return Calendar.getInstance();
        }
    
    }
    

    For this to work properly and be able to mock the instance creation via the static instance creator, your tests should look like this:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest( { SomeClass.class } )
    public class SomeClassTest {
    
        private static final int YEAR  = 2020;
        private static final int MONTH = Calendar.JANUARY;
        private static final int DAY   = 1;
    
        private SomeClass someClass;
    
        @Before
        public void setUp() throws Exception {
            Calendar instance = Calendar.getInstance();
            instance.set(YEAR, MONTH, DAY);
            PowerMockito.mockStatic(Calendar.class);
            PowerMockito.when(Calendar.getInstance()).thenReturn(instance);
            someClass = new SomeClass();
        }
    
        @Test
        public void testDoSomething() {
            Calendar mocked = someClass.createInstance();
            assertNotNull(mocked);
            assertEquals(YEAR, mocked.get(Calendar.YEAR));
            assertEquals(MONTH, mocked.get(Calendar.MONTH));
            assertEquals(1, mocked.get(Calendar.DAY_OF_WEEK_IN_MONTH));
        }
    
    }
    

    Key points here are the following:

    1. @PrepareForTest( { SomeClass.class } ) contains the class that is under test (in our case SomeClass).
    2. Calendar is statically mocked using PowerMock and a new real instance is returned (the one created in the setUp method).

    You can go ahead and use this example which works correctly as a template to adjust your tests.