0

How do I set an expectation on a final method if I can't safely invoke that method at all? PowerMock is supposed to ensure the invocation is mocked, but I can't even get to that stage:

WithFinal.java:

public class WithFinal {
    public final void finalMethod() {
        throw new RuntimeException();
    }
}

CallsFinal.java:

public class CallsFinal {
    private WithFinal withFinal;

    public CallsFinal(WithFinal withFinal) {
        this.withFinal = withFinal;
    }

    public void callFinal() {
        withFinal.finalMethod();
    }
}

PowerMockTest.java:

import org.easymock.EasyMock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.core.classloader.annotations.PrepareForTest;

import static org.powermock.api.easymock.PowerMock.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest(CallsFinal.class)
public class PowerMockTest {
    @Test public void testFinal() {
        WithFinal mock = createMock(WithFinal.class);
        CallsFinal callsFinal = new CallsFinal(mock);
        mock.finalMethod();
        EasyMock.expectLastCall().atLeastOnce();
        replay(mock);
        callsFinal.callFinal();
        verify(mock);
    }
}

I get a RuntimeException on the very first call to mock.finalMethod(), which makes sense, but I thought the whole point of PowerMock was to make this possible?

lmm
  • 17,386
  • 3
  • 26
  • 37

2 Answers2

1

There was a simple mistake in the test class: instead of @PrepareForTest(CallsFinal.class), it should have been @PrepareForTest(WithFinal.class).

PowerMock only requires that the calling class be prepared for test when mocking a system class from the JRE; otherwise, it's the class to be mocked itself that needs to get prepared.

Finally, I will mention there is another mocking library that can be used here, which I happen to develop: JMockit. With it, the test can be written as:

import org.junit.*;
import mockit.*;

public class JMockitTest {
    @Tested CallsFinal callsFinal;
    @Injectable WithFinal mock;

    @Test public void testFinal() {
        new Expectations() {{ mock.finalMethod(); }};

        callsFinal.callFinal();
    }
}
Rogério
  • 16,171
  • 2
  • 50
  • 63
0

Using PowerMock, you can mock skip a internal method call instead of direct method call.

For example you want to test callFinal method of CallsFinal class which internally calling finalMethod of WithFinal class. So in this case if you don't want to instantiate WithFinal class then you need to mock WithFinal object to skip internal call for finalMethod.

ManojP
  • 6,113
  • 2
  • 37
  • 49