Blog

  • 2024
  • 2023
  • 2022
  • 2021
  • 2020
  • 2019
  • 2018
  • 2017
  • 2016
  • 2015
  • 2014
  • 2013
  • 2012




Usually we use mockito for creating our test spies, because this test spy framework is effective and easy to use. Unfortunately creating spies for final classes is not supported.

In our case we wanted to fake a return value of a java.lang.reflect.Method, which is final:

import java.lang.reflect.Method;
 
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
 
public class MethodTest {
  ...
 
  final Method spy = spy(METHOD);
  when(spy.getName()).thenReturn("unknown");
 
  final SerializableMethod uut = new SerializableMethod(spy);
 
  ...
}

In the code snippet "METHOD" is a reference to a Method instance.
SerializableMethod is the unit-under-test (UUT) that holds a reference to the mocked java.lang.reflect.Method instance.

Using mockito will show the following stack trace:

Caused by: org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class java.lang.reflect.Method
Mockito cannot mock/spy following:
  - final classes
  - anonymous classes
  - primitive types
	at test.de.smartics...MethodTest.createUut(MethodTest.java)
	... 26 more

The exception states loud and clear that mockito is not created for mocking final classes.

Now PowerMock comes for rescue. PowerMock adds (among other things) the ability to mock final classes to mockito. Let's have a look how the snippet from above needs to be changed in order to use PowerMock:

import java.lang.reflect.Method;
 
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
 
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
 
...
 
@RunWith(PowerMockRunner.class)
@PrepareForTest(SerializableMethod.class)
public class MethodTest {
  ...
 
    final Method spy = spy(METHOD);
    when(spy.getName()).thenReturn("unknown");
 
    final SerializableMethod uut = new SerializableMethod(spy);
 
  ...
}

So this are the changes: All we have to do is use the PowerMockRunner and instruct PowerMock to prepare our class that uses the spy class with PrepareForTest (for details on preparing classes for using system classes – like java.lang.reflect.Method – , please refer to Mocking system classes). Then we replace the spy and when methods of Mockito with their PowerMock counterparts, as you can see with a glance at the imports.

That’s it! (smile)

For Maven users the integration of PowerMock is very simple, you only have to check that the version of mockito matches that of PowerMock as shown in Using PowerMock with Mockito on the PowerMock's Wiki. This is what we use in our example:

<properties>
  <mockito.version>1.9.5</mockito.version>
  <powermock.version>1.5</powermock.version>
</properties>

<dependencies>
  <dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>${mockito.version}</version>
    <scope>test</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>

  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.8.2</version>
    <scope>test</scope>
  </dependency>
</dependencies>

There is only a minor drawback if you are using Eclipse with EclEmma since the current version 2.2 of EclEmma does not notice lines executed with PowerMock. Fortunately Cobertura does. In our case we use

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>cobertura-maven-plugin</artifactId>
  <version>2.5.1</version>
</plugin>

We hope we have shown how easily mockito's capabilities can be extended with PowerMock. Enjoy!


Link

Link

Posts