Since version 3.4.0, Mockito allows us to mock static methods, so you do not need to add powermock as dependency for most of your necessities.
I will not discuss why we should avoid static methods or helper class with static methods, as several articles do it quite well (1, 2, 3, etc..), we need to deal with static methods in the real world of development and mockito helps us to create unit tests when these static methods are involved.
The code
Static helper / util class
We have a static Helper class with two methods (one with arguments and other without).
For our example, we added a very simple code, but usually static methods have code which are harder to predict and not always junit friendly.
public class GreetingsUtil {
public static String sayFormalGoodbye() {
return "Farewell";
}
public static String getFormalHello(final String name) {
return "Hello " + name;
}
}
Full code available in the example repo in github
Our class
And now, the code which uses the helper class
public class PolitePerson {
public String startConversationWith(final String name) {
return GreetingsUtil.getFormalHello(name) + "!";
}
public String finishConversation() {
return GreetingsUtil.sayFormalGoodbye() + "!";
}
}
Full code available in the example repo in github
Add dependency to mockito inline
Usually for Junit5 and Mockito, we add the mockito-core
dependency, but in this case we need to use mockito-inline
to enable static mocking.
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.6.28</version>
</dependency>
The complete version of the pom.xml
file can be found in the examples repo in github.
As you can see, I use version 3.6.28, which was the latest version available at this time. Check https://mvnrepository.com/artifact/org.mockito/mockito-inline to verify if a newer one is available when you read this article.
Unit test
Our unit tests for need to test both methods.
Creating a test mocking a static method with no arguments
@Test
void shouldFinishConversation() {
//given the object we want to test
PolitePerson politePerson = new PolitePerson();
// we use a try-with-resources block
try (MockedStatic<GreetingsUtil> greetingsUtilMockedStatic = mockStatic(GreetingsUtil.class)) {
//given part: pay attention that inside the when we use a method reference
greetingsUtilMockedStatic.when(GreetingsUtil::sayFormalGoodbye).thenReturn("Bye");
//when part: we call the part of the real code which uses the static method
final String goodbyeMessage = politePerson.finishConversation();
//then part: we verify our mocked method is called and the class does its part (in this case, adding the "!")
assertEquals("Bye!", goodbyeMessage);
}
}
Full code available in the example repo in github
Some notes about the code above:
- We statically imported the method
mockStatic
(and others). - The try-with-resources part is a bit verbose and forces us to create most of the code inside the
try
block. - The mocked method uses a method reference, in the next example, we show how to change behavior based in the argument.
Creating a test mocking a static method with arguments
@Test
void shouldStartConversation() {
//given the object we want to test
PolitePerson politePerson = new PolitePerson();
// we use a try-with-resources block
try (MockedStatic<GreetingsUtil> greetingsUtilMockedStatic = mockStatic(GreetingsUtil.class)) {
//given part: pay attention that inside the when we verify the given argument is equals to "John"
greetingsUtilMockedStatic.when(() -> GreetingsUtil.getFormalHello(eq("John"))).thenReturn("Hello John");
//when part: we call the part of the real code which uses the static method
final String helloMessage = politePerson.startConversationWith("John");
//then part: we verify our mocked method is called and the class does its part (in this case, adding the "!")
assertEquals("Hello John!", helloMessage);
}
}
Full code available in the example repo in github
Some notes about the code above:
- We, again, statically imported the method
mockStatic
(and others). - We use a lambda expression inside the when
- We are testing if the given argument to our static mocked test is equals to “John”
Bonus: Mocking constructors
Some methods create new objects inside it and for tests, we could want to control how these internal objects behave. For that, in Mockito 3.5.0+ you can also mock constructors.
@Test
void shouldForceAnInformalPerson() {
// we use a try-with-resources block
try (MockedConstruction politePersonConstructionMocked = mockConstruction(PolitePerson.class)) {
// given part: in our example, we create the new object, but this part could be inside a method call
PolitePerson mockedPolitePerson = new PolitePerson();
// given part: when the mock PolitePerson finish conversation is called, an informal goodbye is sent
when(mockedPolitePerson.finishConversation()).thenReturn("Take it easy");
// when part: call the method
final String informalGoodbyeMessage = mockedPolitePerson.finishConversation();
// then part: we verify our fake message is returned and we verify the mock is called only once
assertEquals("Take it easy", informalGoodbyeMessage);
verify(mockedPolitePerson, times(1)).finishConversation();
}
}
Full code available in the example repo in github
Some notes about the code above:
- Given part: we also created the object here, but in the real world, the object creation is part of the “then” part.
- We use verify method from mockito to test the method is called only once. The
times(1)
is not needed for the value 1, but I prefer to put it explicitly to make the code more precise.
If you found any error or want to help me to improve this article, please comment the pull request