PowerMockito

PowerMock Mock Static Method Example

In the Mockito Tutorial for Beginners, we did a general introduction to the Mockito mocking framework for JUnit tests. One the things that we did not see, was the mocking of static methods. That is because Mockito doesn’t allow to do that.

To solve this, we will use PowerMock, a framework that extends Mockito’s functionalities (and other mocking frameworks’ also), which allows, among other things, static method mocking.

For this example, we will use:

  • Java 1.7.0
  • Eclipse Mars 2, release 4.5.2.
  • JUnit 4.
  • PowerMock 1.6.5 for Mockito, and its dependencies.
Tip
You may skip project creation and jump directly to the beginning of the example below.

1. Project creation

Go to “File/New/Java Project”. You will be asked to enter a name for the project. Then, press “Next”, not “Finish”.

In the new window that has appeared, go to “Libraries” tab, select “Add library” button, and then select “JUnit”, as shown in the following images below:

1. Adding libraries to the project

2. Adding JUnit as library

With this, we have added the required dependencies for JUnit testing. You can now finish the project creation.

Now, right click the folder icon in the Package Explorer, and select “New/Source Folder”, and enter the name you want to give to the test folder.

3.Creating folder for tests

1.1. Powermock installation

Apart from JUnit and its dependencies, we need several more libraries.

4. Adding PowerMock and dependencies to build path

2. Base code

Let’s suppose that we have to develop a class for making a query against a database. We could do something similar to the following:

DatabaseReader.java

package com.javacodegeeks.powermock.staticmethod;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DatabaseReader {

    public static final String CONNECTION = "jdbc:mysql://localhost/testdb";
    
    public static String getById(int id) throws SQLException {
        String query = "SELECT * FROM Foo WHERE Id = ?";
        Connection connection = DriverManager.getConnection(CONNECTION);
        PreparedStatement preparedStatement = connection.prepareStatement(query);
        preparedStatement.setInt(1, id);
        ResultSet resultSet = preparedStatement.executeQuery();
        
        resultSet.next();
        
        String result = resultSet.getString(0);
        
        resultSet.close();
        preparedStatement.close();
        connection.close();
        
        return result;
    }
}

We won’t need a real database (remember that we are mocking).

3. Mocking the method

This is how we would mock our getById static method, using PowerMock:

package com.javacodegeeks.powermock.staticmethod;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.verifyStatic;

import java.sql.SQLException;

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

@RunWith(PowerMockRunner.class)
@PrepareForTest(DatabaseReader.class)
public class DatabaseReaderTest {

    @Test
    public void testGetById() {
        int inputId = 1;
        String returnValue = "JavaCodeGeeks";

        mockStatic(DatabaseReader.class);

        try {
            when(DatabaseReader.getById(inputId))
                .thenReturn(returnValue);

            String actual = DatabaseReader.getById(inputId);
            
            verifyStatic();
            assertEquals(returnValue, actual);
        } catch (SQLException e) {
            fail("No exception should be thrown.");
        }
    }
    
}

Which is the main difference with “normal” mocking? Is that we are specifying that a class’ static function will be mocked, instead of creating a mock instance and adding behavior to a function. That is done with mockStatic() method and @PrepareForTest annotation, and, then, the behavior is defined as always with when(), but accessing the method statically. Note that we also need to run the test case with @RunWith(PowerMockRunner.class) annotation, and also that we can make the verification of the static method call with verifyStatic().

Take into account that the following test would work:

DatabaseReaderTest.java

@Test
public void testGetById() {
    int inputId = 1;
    String returnValue = "JavaCodeGeeks";
        
    DatabaseReader databaseReaderMock = Mockito.mock(DatabaseReader.class);
    try {
        when(databaseReaderMock.getById(inputId))
            .thenReturn(returnValue);
            
        String actual = DatabaseReader.getById(inputId);
            
        assertEquals(returnValue, actual);
    } catch (SQLException e) {
        fail("No exception should be thrown.");
    }
}

// ...

Without the need of PowerMock or any other special mocking technique for the method. But it would not make any sense to test a static method as a object method, since it’s supposed to be called as a class method, so the test would not reflect a real case.

3.1. Mocking the database connection

We can go further and mock what happens inside getById() method, inside of just adding a predefined behavior to it. For that, we would have to mock the database connection, done with DriverManager.getConnection() method. With Mockito, we couldn’t mock the method in that way. But, as we have seen with PowerMock, we can mock it as any other method.

DatabaseReaderTest.java

// ...

@Test
public void testGetByIdMockDatabase() {
    String query = "SELECT * FROM Foo WHERE Id = ?";
    int inputId = 1;
    String returnValue = "JavaCodeGeeks";
        
    Connection connectionMock = Mockito.mock(Connection.class);
    PreparedStatement preparedStatementMock = Mockito.mock(PreparedStatement.class);
    ResultSet resultSetMock = Mockito.mock(ResultSet.class);
        
    mockStatic(DriverManager.class);
    try {
        when(DriverManager.getConnection(DatabaseReader.CONNECTION))
            .thenReturn(connectionMock);

        when(connectionMock.prepareStatement(query))
            .thenReturn(preparedStatementMock);
            
        when(preparedStatementMock.executeQuery())
            .thenReturn(resultSetMock);

        when(resultSetMock.next())
            .thenReturn(true);
            
        when(resultSetMock.getString(0))
            .thenReturn(returnValue);
            
        String actual = DatabaseReader.getById(inputId);
            
        verify(connectionMock).prepareStatement(query);
        verify(preparedStatementMock).executeQuery();
        verify(resultSetMock).next();
        verify(resultSetMock).getString(0);
        verifyStatic();

        assertEquals(returnValue, actual);
    } catch (SQLException e) {
        fail("No exception should be thrown.");
    }
}

// ...

As you can see, apart from mocking the DriverManager.getConnection() static method, we have to create the mocks of the other objects used to make the query, combining PowerMock’s static mocking, and Mockito’s default features; but the concept is the same: mocking functions that “belong” to class, and not necessarily to its instances. Without PowerMock, there would not be way to test getById() method with mocks, and a real database would be required.

4. Summary

This tutorial has shown how to mock static methods with PowerMock, a feature that is not available in the Mockito framework. We have seen that is specially useful when a method depends on a static method of another class.

5. Download the Eclipse Project

This was an example of mocking static methods with PowerMock.

Download
You can download the full source code of this example here: PowerMockMockStaticMethod

Julen Pardo

Julen holds his Bachelor's Degree in Computer Engineering from Mondragon Unibertsitatea, in Spain. Currently he is working in Munich, Germany, as Software Engineer. He contributes to open source projects with plugins, and he also develops his own, open-source projects. Julen is continuously trying to learn and adopt Software Engineering principles and practices to build better, more secure, readable and maintainable software.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button