Mocking Static Methods in Java with Mockito
In Java, mocking static methods can be a bit tricky as Mockito, the popular mocking framework, does not support mocking static methods out-of-the-box. However, there are some workarounds that can be used to mock static methods using Mockito. In this article, we will explore two approaches to achieve this.
Approach 1: Using PowerMockitoPowerMockito is an extension of Mockito that provides additional functionalities, including the ability to mock static methods. To use PowerMockito, you need to add the PowerMockito and PowerMockito-JUnit dependencies to your project.
<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-mockito2</artifactId> <version>{powermock-version}</version> <scope>test</scope></dependency>
Once the dependencies are added, you can use PowerMockito to mock the static methods. Here's an example:
import org.powermock.api.mockito.PowerMockito;public class MyStaticClass { public static String getGreeting() { return "Hello"; }}// Test class@RunWith(PowerMockRunner.class)public class MyStaticClassTest { @Test public void testMockStaticMethod() { PowerMockito.mockStatic(MyStaticClass.class); Mockito.when(MyStaticClass.getGreeting()).thenReturn("Mocked greeting"); String greeting = MyStaticClass.getGreeting(); assertEquals("Mocked greeting", greeting); }}
In the above example, we have a class MyStaticClass
with a static method getGreeting()
. We use PowerMockito.mockStatic()
to mock the static class and Mockito.when()
to define the behavior of the mocked static method.
Another approach to mock static methods is by using dependency injection and refactoring the code to make it more testable. This approach involves creating an interface for the static method, implementing the interface in a separate class, and then injecting the implementation into the class under test.
Here's an example:
public interface GreetingService { String getGreeting();}public class MyStaticClass { private static GreetingService greetingService = new DefaultGreetingService(); public static String getGreeting() { return greetingService.getGreeting(); } // Setter method for testing purposes public static void setGreetingService(GreetingService service) { greetingService = service; }}public class DefaultGreetingService implements GreetingService { public String getGreeting() { return "Hello"; }}// Test classpublic class MyStaticClassTest { @Test public void testMockStaticMethod() { GreetingService mockGreetingService = Mockito.mock(GreetingService.class); Mockito.when(mockGreetingService.getGreeting()).thenReturn("Mocked greeting"); MyStaticClass.setGreetingService(mockGreetingService); String greeting = MyStaticClass.getGreeting(); assertEquals("Mocked greeting", greeting); }}
In this approach, we create an interface GreetingService
that defines the static method getGreeting()
. We then implement the interface in a separate class DefaultGreetingService
. The MyStaticClass
class has a static field of type GreetingService
and uses it to get the greeting. In the test, we mock the GreetingService
interface using Mockito and inject the mock implementation into MyStaticClass
using the setGreetingService()
method.
The following sequence diagram illustrates the flow of the second approach:
sequenceDiagram participant TestClass participant MyStaticClass participant GreetingService participant DefaultGreetingService TestClass ->> MyStaticClass: Mock static method MyStaticClass ->> GreetingService: getGreeting() GreetingService ->> DefaultGreetingService: getGreeting() DefaultGreetingService -->> GreetingService: "Hello" GreetingService -->> MyStaticClass: "Hello" MyStaticClass -->> TestClass: "Hello"
Class DiagramThe class diagram for the second approach looks like this:
classDiagram class MyStaticClass { - static GreetingService greetingService + static String getGreeting() + static void setGreetingService(GreetingService) } class DefaultGreetingService { + String getGreeting() } interface GreetingService { + String getGreeting() } GreetingService --|> DefaultGreetingService MyStaticClass <-- GreetingService
In the class diagram, MyStaticClass
has a static field greetingService
of type GreetingService
. It also has the static method getGreeting()
and the setter method `set