javapowermockeasymock

Throw Exception Whenever Package Protected Static Method Is Called Using PowerMock (EasyMock)


I'm trying to throw an assertion exception whenever the TimeZone.getDefaultRef() method is called, to basically show that this method is never called during the test. The problem is that it's package protected and static, so I think I'm forced to use PowerMock. Here's my attempt:

@RunWith(PowerMockRunner.class)
@PrepareForTest(TimeZone.class)
public class RandomTestingClass {
    @Before
    public void setup() {
        PowerMock.mockStaticPartialNice(TimeZone.class, "getDefaultRef")
        PowerMock.expectPrivate(TimeZone.class, 
            TimeZone.class.getDeclaredMethod("getDefaultRef")).andStubThrow(new AssertionError());
        PowerMock.replay(TimeZone.class)
    }

    @Test
    public void randomTestThatShouldFailBecauseMethodCallsGetDefaultRefMethod() {
        Calendar.getInstance();
    }

    @Test
    public void randomTestThatShouldPassBecauseMethodDoesNotCallGetDefaultRefMethod() {
        Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    }

    @After
    public void after() {
        PowerMock.verify(TimeZone.class);
    {

I'm getting the error java.lang.IllegalStateException: no last call on a mock available, which I've definitely seen before but am not sure how to fix in this context. I'm also open to any other more elegant way to accomplish this. To sum up:

  1. Test should fail if Timezone.getDefaultRef() is ever called
  2. Test shouldn't fail just because the method is never called (EasyMock is expecting the method but it never comes)
  3. One test failing shouldn't affect the other tests
  4. Everything else about the TimeZone class should operate normally

Solution

  • I am trying to find a workaround but the quick answer is that the method is not mocked. The real method is called instead during the expectation.

    PowerMock can't mock classes loaded by the bootstrap class loader. TimeZone is one of those.

    The solution is to mock with is calling it. It's explained here. It says you need to prepare the class calling the system class instead of the system class.

    But in your case, I'm not sure you can. Because you want to know if something somewhere is calling your class. So you can't prepare whatever is using TimeZone if that is was you are looking for. Unless you have a limited scope of possible callers.