We all know that unit tests must not interact with external dependencies—databases, HTTP services, the filesystem, etc. You must resort to mocking those dependencies. This presents a problem: sometimes you have to mock code you didn’t write, presented in the form of static methods.
In this post, you’ll learn how to deal with this challenge in the Java world using the popular Mockito library.
We’ll open the post by answering the “why” question. Why would you want to mock static methods in the first place? As you’ll see, some people argue that trying to mock static methods isn’t a good idea to start with, so let’s examine whether that’s the case.
With the “why” out of our way, let’s get to the how. We’ll walk you through three possible solutions for mocking the static method, including
- one that involves avoiding mocking said methods,
- a second one that uses a third-party tool, and
- a final one that relies only on Mockito itself.
Before wrapping up, we’ll share some final thoughts and considerations.
Mocking Static Methods: Why Would You Want to Do It?
If you Google “Mockito mock static method,” you’ll find people saying you can’t—or shouldn’t—mock static methods. In a way, they’re right.
One of the premises of unit testing is that to use it, you must write code in a particular style that leads itself to be testable. This style favors dependency injection—i.e., expressing dependencies in the form of interfaces that can be substituted for “fake implementations” during testing time.
This coding style doesn’t mix well with static classes and methods because it relies on instances of the dependencies being passed to consumers.
If the world was perfect, you shouldn’t need to mock static methods. Sadly, that’s not the case. You’ll often find situations requiring you to mock static methods, such as testing code that relies on old APIs whose authors weren’t thinking of dependency injection.
Expand Your Test Coverage
Mocking Static Methods With Mockito: 3 Alternatives
Having covered the fundamentals of mocking static methods, let’s finally see how you can do it.
Mockito didn’t allow mocking static methods for a long time, but this has changed somewhat recently. So, currently, there are three possible alternatives for this:
- The first option is creating wrapper objects.
- The second one relies on a third-party package called PowerMock.
- Finally, you can now do this with Mockito itself.
Let’s cover each option.
Option #1: Create Wrapper Objects
Suppose you have a class like this:
class StringCalculatorStatic { public static int add(String numbers) { String[] parts = numbers.split(","); int sum = 0; for (String part : parts) { int number = Integer.parseInt(part); sum += number; } return sum; } }
This is an incomplete solution to the StringCalculator Kata by Roy Osherov. As you can see, the method doesn’t interact with any external dependency, so you probably wouldn’t want to mock it in real life. For this example, imagine it does talk to a real dependency.
The first option consists of not mocking the static method at all. Instead, what you’d do is:
- create an interface that exposes the method signature,
- implement the interface creating a class and call the static method inside it, and
- during testing, create a mock for this interface and provide that to the consumer.
Let’s see this in practice. The first step would be to create an interface:
public interface StringCalculator { public int add(String numbers); }
Then, we would have a class that implements the interface and calls the original static method:
public class StringCalculatorImp implements StringCalculator { @override public int add(String numbers) { return StringCalculatorStatic.add(numbers); } }
In testing time, you’d just have to mock the interface:
StringCalculator calc = Mockito.mock(StringCalculator.class); Mockito.when(calc.add("4,6")).thenReturn(10);
Of course, if you’re the owner of the offending class, a viable solution would be to make the method not static. However, that constitutes a breaking change.
A more gentle solution is what we just presented: creating a wrapping class and slowly replacing the old implementation with the new, making sure nothing breaks in the process.
Option #2: Use PowerMock
The previous option is a viable alternative and a legitimate and recommended pattern to deal with static methods when unit testing. However, you might have felt it’s kind of cheating since we’re not actually mocking static methods.
In this second alternative, we’ll explore PowerMock. As stated in its GitHub readme:
PowerMock is a framework that extends other mock libraries such as EasyMock with more powerful capabilities.
With PowerMock, we can add to Mockito the capability of mocking static methods. This can quickly be done this way:
mockStatic(StringCalculatorStatic.class); expect(StringCalculatorStatic.add("1,2,3")).andReturn(6);
- First, we instruct PowerMock to understand which class contains the static methods we want to mock.
- During testing, we set up the expectations in a way not that different from what we do with regular Mockito.
I won’t get into much detail about installing and configuring PowerMock. Though very versatile, it’s a third-party package.
As it turns out, the most recent versions of Mockito allow the mocking of static methods without any additional packages, so that’s the preferable approach.
Option #3: Just Vanilla Mockito
Nowadays, using Mockito to mock static methods is very easy.
- First, make sure to import the org.mockito.MockedStatic; namespace.
- When declaring your dependencies, you should declare dependencies to mockito-inline instead of the mockito-core library.
- Finally, use the mockStatic method to mock our original, static method:
try (MockedStatic<StringCalculatorStatic> mockedStatic = Mockito.mockStatic(StringCalculatorStatic.class)) { mockedStatic.when(() -> StringCalculatorStatic.add("1,2,3")).thenReturn(7); System.out.println("Result: " + StringCalculatorStatic.add("1,2,3")); }
In the example above, I’m mocking the add method, so it incorrectly returns 7 to prove it’s being mocked:
Bonus Option: Refactor Your Code
Before wrapping up, here’s a final bonus tip regarding static methods. The advice is simple—though not necessarily easy—also not surprising if you’ve been paying attention: avoid having to mock static methods.
Sometimes, there’s no other way. For instance, you might find yourself in a scenario where performance concerns are so paramount that you have to avoid instance allocations at all costs. So, static methods might be preferable in this situation.
Generally speaking, though, if you’re trying to write code that is modular and easy to navigate and change—in other words, testable code—you should stay clear of static methods and prefer a style of coding that relies on instances and dependency injection.
Feeling the need to mock static methods is a valuable piece of feedback. In a certain way, it’s like your code is telling you it’s not object-oriented enough. If that’s the case, refactor your code, so it makes more use of object orientation, dependency injection, and the best practices that lead to testable code.
Conclusion
If you’re familiar with the concept of the testing pyramid, you know that most of your automated testing efforts should focus on unit tests.
Writing unit tests isn’t always a walk in the park. It involves having your codebase conform to a specific style of coding.
Such style relies on dependency injection, which doesn’t play well with static methods. However, you might find yourself in situations where mocking static methods is the only solution.
In such cases, you can use the popular Mockito mocking library to mock static methods to perform your unit tests without much pain. As you’ve seen, Mockito used to forbid such practice, and you had to either rely on a third-party tool or resort to the wrapper object pattern. However, recent versions of Mockito added that much-anticipated capability.