Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I have to extend PowerMockTestCase?

The below test throws java.lang.IllegalStateException: no last call on a mock available when I don't extend from the PowerMockTestCase.

The error disappears as soon as I extend from PowerMockTestCase. Why exactly is this happening?

import static org.junit.Assert.assertEquals;

import org.easymock.EasyMock;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;

@PrepareForTest({ IdGenerator.class, ServiceRegistartor.class })
public class SnippetTest extends PowerMockTestCase{

    @org.testng.annotations.Test
    public void testRegisterService() throws Exception {
        long expectedId = 42;

        // We create a new instance of test class under test as usually.
        ServiceRegistartor tested = new ServiceRegistartor();

        // This is the way to tell PowerMock to mock all static methods of a
        // given class
        PowerMock.mockStatic(IdGenerator.class);

        /*
         * The static method call to IdGenerator.generateNewId() expectation.
         * This is why we need PowerMock.
         */
        EasyMock.expect(IdGenerator.generateNewId()).andReturn(expectedId).once();

        // Note how we replay the class, not the instance!
        PowerMock.replay(IdGenerator.class);

        long actualId = tested.registerService(new Object());

        // Note how we verify the class, not the instance!
        PowerMock.verify(IdGenerator.class);

        // Assert that the ID is correct
        assertEquals(expectedId, actualId);
    }

}
like image 400
Ajay Avatar asked Sep 29 '22 17:09

Ajay


2 Answers

While using PowerMock for static mocking, there is a class level instrumentation happening to make your mocking work. PowerMockTestCase class has a code (method beforePowerMockTestClass()) to switch your regular class loader to powermock class loader which orchestrates mocking injection. Hence you need to extend this class for static mock to work.

like image 93
Prabakar K Avatar answered Oct 06 '22 20:10

Prabakar K


You need to have the PowerMock class-loaders configured so that the static classes can be intercepted (defined using the @PrepareForTest annotation).

You don't have to extend from PowerMockTestCase. For most cases you can also configure TestNG with a PowerMockObjectFactory instead:

@PrepareForTest({ IdGenerator.class, ServiceRegistartor.class })
public class SnippetTest {

   @ObjectFactory
   public IObjectFactory objectFactory() {
      return new PowerMockObjectFactory();
   }

   @org.testng.annotations.Test
   public void testRegisterService() throws Exception {
      ...
   }
}
like image 45
tony.ganchev Avatar answered Oct 06 '22 20:10

tony.ganchev