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.
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:
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.
1.1. Powermock installation
Apart from JUnit and its dependencies, we need several more libraries.
- Download them:
- Place them inside your working directory, for example, in a lib directory in the directory root.
- Refresh the Package Explorer in Eclipse (F5).
- Now, a new lib directory should be displayed, with all the jar files. Select all of them, right click on them an select “Build Path/Add to Build Path” (shown in image below).
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.
You can download the full source code of this example here: PowerMockMockStaticMethod