This is the 18th day of my participation in the August Challenge

1. An overview of the

Mocking frameworks have long been used as a useful practice to conduct unit tests, especially when Mockito has been dominating in recent years.

And in order to promote decent code design and keep the public API simple, some required features are intentionally omitted. In some cases, however, these shortcomings force testers to write tedious code just to make simulation creation feasible.

This is thePowerMockWhere the framework comes into play.

PowerMockito is an extended API for PowerMock that supports Mockito. It provides the ability to use the Java reflection API ina simple way to overcome Mockito’s problems, such as the lack of ability to emulate final, static, or private methods.

This article introduces the PowerMockito API and its application to the tests.

2. Prepare

The first step in integrating PowerMock support for Mockito is to include the following two dependencies in the Maven POM file:

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>1.6.4</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito</artifactId>
    <version>1.6.4</version>
    <scope>test</scope>
</dependency>
Copy the code

Next, we need to prepare our test cases using PowerMockito by applying the following two comments:

@RunWith(PowerMockRunner.class)
@PrepareForTest(fullyQualifiedNames = "com.baeldung.powermockito.introduction.*")
Copy the code

The fullyQualifiedNames element in the @preparefortest annotation represents an array of fullyQualifiedNames of the types we want to emulate. In this case, we use a wildcard package name to tell PowerMockito prepared com. Baeldung. PowerMockito. The introduction of all types in the package to mock.

3. Simulate constructors and final methods

In this section, we’ll demonstrate how to get a mock instance instead of a real one when instantiating a class using the new operator, and then use that object to simulate the final method. The constructor and final method of the collaboration class will be simulated, defined as follows:

public class CollaboratorWithFinalMethods {
    public final String helloMethod(a) {
        return "Hello World!"; }}Copy the code

First, we create a mock object using the PowerMockito API:

CollaboratorWithFinalMethods mock = mock(CollaboratorWithFinalMethods.class);
Copy the code

Next, set an expected value that tells us that whenever we call the class’s no-argument constructor, we should return a mock instance instead of a real one:

whenNew(CollaboratorWithFinalMethods.class).withNoArguments().thenReturn(mock);
Copy the code

Let us by using its default constructor instantiation CollaboratorWithFinalMethods class to see how the structure simulation works, and then verify PowerMock behavior:

CollaboratorWithFinalMethods collaborator = new CollaboratorWithFinalMethods();
verifyNew(CollaboratorWithFinalMethods.class).withNoArguments();
Copy the code

In the next step, set the expectation to the final method:

when(collaborator.helloMethod()).thenReturn("Hello Baeldung!");
Copy the code

Then execute this method:

String welcome = collaborator.helloMethod();
Copy the code

The following assertion confirms that the helloMethod method has been called on the collaborator object and returns the value of the simulated expected setting: **

Mockito.verify(collaborator).helloMethod();
assertEquals("Hello Baeldung!", welcome);
Copy the code

The mockito.spy (T object) method may come in handy if we want to emulate a specific final method rather than all final methods within an object. Section 5 illustrates this.

4. Simulate static methods

Suppose we want to simulate a static method called CollaboratorWithStaticMethods class. This class is declared as follows:

public class CollaboratorWithStaticMethods {
    public static String firstMethod(String name) {
        return "Hello " + name + "!";
    }

    public static String secondMethod(a) {
        return "Hello no one!";
    }

    public static String thirdMethod(a) {
        return "Hello no one again!"; }}Copy the code

To simulate these static methods, we need to register closed classes using the PowerMockito API:

mockStatic(CollaboratorWithStaticMethods.class);
Copy the code

Alternatively, we can use the mockito.spy (Class Class) method to simulate specific methods, as shown in the next section.

Next, you can set the expected value to define what the method should return when called:

when(CollaboratorWithStaticMethods.firstMethod(Mockito.anyString()))
  .thenReturn("Hello Baeldung!");
when(CollaboratorWithStaticMethods.secondMethod()).thenReturn("Nothing special");
Copy the code

Or the thirdMethod method may be set to throw an exception when called:

doThrow(new RuntimeException()).when(CollaboratorWithStaticMethods.class);
CollaboratorWithStaticMethods.thirdMethod();
Copy the code

Now, execute the first two methods:

String firstWelcome = CollaboratorWithStaticMethods.firstMethod("Whoever");
String secondWelcome = CollaboratorWithStaticMethods.firstMethod("Whatever");
Copy the code

Instead of calling a member of the real class, the above call delegates to the mock method. The following assertions prove that the simulation is in effect:

assertEquals("Hello Baeldung!", firstWelcome);
assertEquals("Hello Baeldung!", secondWelcome);
Copy the code

We can also verify the behavior of the mock method, including the number of times the method is called. In this case, firstMethod has been called twice and secondMethod has never been called:

verifyStatic(Mockito.times(2));
CollaboratorWithStaticMethods.firstMethod(Mockito.anyString());
        
verifyStatic(Mockito.never());
CollaboratorWithStaticMethods.secondMethod();
Copy the code

Note: The verifyStatic method must be called correctly before any static method validation PowerMockito knows that continuous method invocations are something that needs to be validated.

Finally, the static thirdMethod method should throw a RuntimeException, as declared earlier on the simulation. It is verified by the expected element of the @test annotation:

@Test(expected = RuntimeException.class)
public void givenStaticMethods_whenUsingPowerMockito_thenCorrect(a) {
    // other methods   
       
    CollaboratorWithStaticMethods.thirdMethod();
}
Copy the code

5. Partial simulation

The PowerMockito API allows you to emulate portions of the class using spy methods instead of the entire class. The following classes will use collaborators to illustrate PowerMock’s partial emulation support:

public class CollaboratorForPartialMocking {
    public static String staticMethod(a) {
        return "Hello Baeldung!";
    }

    public final String finalMethod(a) {
        return "Hello Baeldung!";
    }

    private String privateMethod(a) {
        return "Hello Baeldung!";
    }

    public String privateMethodCaller(a) {
        return privateMethod() + " Welcome to the Java world."; }}Copy the code

Let’s start by simulating a staticMethod named staticMethod in the class definition above. PowerMockito apis used by the first of all, some simulation CollaboratorForPartialMocking class and set expectations for its static method:

spy(CollaboratorForPartialMocking.class);
when(CollaboratorForPartialMocking.staticMethod()).thenReturn("I am a static mock method.");
Copy the code

Then execute the static method:

returnValue = CollaboratorForPartialMocking.staticMethod();
Copy the code

Simulation behavior verification is as follows:

verifyStatic();
CollaboratorForPartialMocking.staticMethod();
Copy the code

The following assertions confirm that the mock method has actually been called by comparing the return value with the expected value:

assertEquals("I am a static mock method.", returnValue);
Copy the code

Now verify final and private methods. To illustrate a partial emulation of these methods, we need to instantiate the class and tell the PowerMockito API to monitor it:

CollaboratorForPartialMocking collaborator = new CollaboratorForPartialMocking();
CollaboratorForPartialMocking mock = spy(collaborator);
Copy the code

The object created above is used to demonstrate simulation of final and private methods. We will now handle the final method by setting expectations and calling this method:

when(mock.finalMethod()).thenReturn("I am a final mock method.");
returnValue = mock.finalMethod();
Copy the code

Partially simulating the behavior of the method is proved:

Mockito.verify(mock).finalMethod();
Copy the code

The test verifies that calling the finalMethod method returns a value that matches the expected value:

assertEquals("I am a final mock method.", returnValue);
Copy the code

A similar process applies to private methods. The main difference is that we cannot call this method directly from the test case. Basically, private methods will be called by other methods from the same class. In CollaboratorForPartialMocking class, privateMethod method will be used by privateMethodCaller method calls, we will use the latter as a delegate. Let’s start with expectations and calls:

when(mock, "privateMethod").thenReturn("I am a private mock method.");
returnValue = mock.privateMethodCaller();
Copy the code

The mock for the private method is confirmed:

verifyPrivate(mock).invoke("privateMethod");
Copy the code

The following tests ensure that calling a private method returns the same value as expected:

assertEquals("I am a private mock method. Welcome to the Java world.", returnValue);
Copy the code

Six, the summary

This article introduced the PowerMockito API and demonstrated its use in solving some of the problems that developers encounter when using the Mockito framework.