Monday, April 25, 2016

Mocking with PowerMock and Mockito

The PowerMock extends Mockito and EasyMock frameworks. The vast advantage of the PowerMock is possibility to mock static and final classes and even private methods and members.

This post does not pretend to be a tutorial for the PowerMock. It just gives several examples of how-to-mock with PowerMock and Mockito.

Maven Dependencies

The following dependencies should be added to pom:
 <mockito.version>1.10.19</mockito.version>  
 <powermock.version>1.6.2</powermock.version>  
 <dependency>  
      <groupId>org.mockito</groupId>  
      <artifactId>mockito-all</artifactId>  
      <version>${mockito.version}</version>  
      <scope>provided</scope>  
 </dependency>  
 <dependency>  
      <groupId>org.powermock</groupId>  
      <artifactId>powermock-module-junit4</artifactId>  
      <version>${powermock.version}</version>  
      <scope>test</scope>  
 </dependency>  
 <dependency>  
      <groupId>org.powermock</groupId>  
      <artifactId>powermock-api-mockito</artifactId>  
      <version>${powermock.version}</version>  
      <scope>test</scope>  
 </dependency>  
Note: If more recent versions already exist, use them instead of the shown here.

Mocking basic

The test class should be annotated with @RunWith(PowerMockRunner.class) annotation:
@RunWith(PowerMockRunner.class)
public class TestSomeService {
... 

To mock an instance of the class MyService use @Mock annotation:
@Mock
private MyService mockedServiceHandler;

Another way to mock an instance is to call method Mockito.mock(MyService.class):
private MyService mockedServiceHandler = Mockito.mock(MyService.class);

If you prefer the second way, add the import of Mockito.* and mock() may be called without Mockito namespace (less of code):
import static org.mockito.Mockito.*;
…
private MyService mockedServiceHandler = mock(MyService.class);

Mocking of static methods

To allow mocking of static methods:
1. Put @PrepareForTest annotation before the test class. The annotation value should contain a class name or list of class names to be mocked:
@PrepareForTest({StaticClassName1.class, StaticClassName2.class…})
or
@PrepareForTest(Static1.class) // A single class without curly brackets
2. Create the class mock:
PowerMockito.mockStatic(StaticClass.class);
Note: A good place for class mocking is a method annotated with @Before.

Mocking of static methods, returning value, is similar to instance methods mocking:
when(StaticClass.staticMethod(Mockito.any(), Mockito.any()...).thenReturn(someResult);

Void static method is mocked just by call to the method from the test:
StaticClass.voidMethod(Mockito.any(), Mockito.any()...);

Void static method, which throws an exception, is mocked like this:
PowerMockito.doThrow(new NullPointerException(errorMsg)).when(StaticClass.class);
StaticClass.voidMethod(Mockito.any(), Mockito.any()...)

There is one more issue to explain before we will see the full code example.

@PowerMockIgnore annotation

Due to PowerMock class loading implementation sometimes tests fail running with linkage errors in the framework classes.

To overcome this put the annotation @PowerMockIgnore on the class level.
This annotation prevents the framework classes from loading.

Put the list of packages/classes or a single package/class into annotation values:
@PowerMockIgnore({"package or class name", "package or class name"})
or 
@PowerMockIgnore("package or class name") // No curly brackets

To prevent loading of the java framework classes:
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
public class TestClass {

If class under test use javax.crypto classes, they should be added into @PowerMockIgnore values as well:
@RunWith(PowerMockRunner.class)
@PowerMockIgnore({"javax.management.*", "javax.crypto.*"})
public class TestClass {
     ...

The full code example

The example code was taken from the real project; ignore the unexplained classes, but look how mocking is done.

Under the test is the method registerParticipant of the class RsvpServiceHandler.

The tested method calls to the service SchedulingCenterClient, which exposes the static method registerParticipant; the SchedulingCenterClient throws an exception in case of failure.
public class RsvpServiceHandler implements RsvpService {
     public RsvpOpBaseResult registerParticipant(RegParticipantRequest request) {
          return RsvpOperationExecutor.execute(
            "registerParticipant", request, RsvpOpErrMessages.FAILED_REGISTER_PARTICIPANT, (r) -> {
                 SchedulingCenterClient.registerParticipant(request.getConferenceID(), request.getParticiantDTO());
                 return RsvpOpBaseResult.okResult();
          });
     }
}

public final class SchedulingCenterClient {
     ...
     public static void registerParticipant(long conferenceId, ParticipantDTO participentDetails) throws WSException {
        // The method implementation is not important, since the method will be mocked
        ...
     }
     ...
}

In order to test RsvpServiceHandler the SchedulingCenterClient should be mocked.

The test class below has two test methods: one for the happy flow, the second - for an error.
Both tests mock the SchedulingCenterClient.registerParticipant, but in the error test an exception is mocked before the call to the static method.
@RunWith(PowerMockRunner.class)
@PrepareForTest(SchedulingCenterClient.class)
@PowerMockIgnore("javax.management.*")
public class TestRsvpHandlerRegisterParticipant {

     private RsvpServiceHandler handler = new RsvpServiceHandler();

     @Before
     public void setUp() throws Exception {
          PowerMockito.mockStatic(SchedulingCenterClient.class);
     }

     @Test
     public void testRegParticipantOk() {
          RegParticipantRequest request = DataSimulator.createRegParticipantRequest(getConferenceId(), true);
          SchedulingCenterClient.registerParticipant(anyLong(), anyObject());
          RsvpOpBaseResult result = handler.registerParticipant(request);
          assertTrue("Wrong operation result on success:", result.isOk());
     }

     @Test
     public void testRegParticipantErrorNullData() {
          String errorMsg = "Mock error";
          RegParticipantRequest request = DataSimulator.createRegParticipantRequest(getConferenceId(), false);
          PowerMockito.doThrow(new NullPointerException(errorMsg)).when(SchedulingCenterClient.class);
          SchedulingCenterClient.registerParticipant(anyLong(), anyObject());
          RsvpOpBaseResult result = handler.registerParticipant(request);
          assertEquals("Wrong error code on failure:", RsvpOpResultCode.INTERNAL_ERROR, result.getResultCode());
          assertEquals("Wrong error message on failure:", errorMsg, result.getMessage());
     }

Mocking of private members

Private class members may be mocked with the MemberModifier class.

Let's fabricate a class Response with the private member of type HttpResponse.
The test mocks the response and its private member httpResponse.
Mocking of the private member is done by assigning to it the mock, created explicitly.
// Class to be mocked 
public class Response {  
   …  
   private HttpResponse httpResponse;  
   ….  
}

// Test class
public class TestResponse {
      @Mock  
      Response fakeResponse;  
      @Mock  
      HttpResponse fakeHttpResponse;
   
      public void testSomething() {
            // Mocking of the private member
            MemberModifier.field(Response.class, "httpResponse").set(fakeResponse, fakeHttpResponse);
            // Test stuff ...
      }
}

See also:

1 comment :

Melony Fisher said...


Hi! Do you know if they make any plugins to assist with SEO? I'm trying to get my blog to rank for some targeted keywords but I'm not seeing very good results. If you know of any please share. Cheers! gmail log in

About the author

My Photo
I trust only simple code and believe that code should be handsome. This is not a matter of technology, but professional approach, consolidated after years of software development. I enjoy to cause things working and feel very happy, when I manage to solve a problem.
Back to Top