You might need to mock the static method in your unit test in some circumstances. In this brief tutorial, we'll learn how to utilize the mockito framework to mock the behavior of a Java static method. Now, version 3.4.0 or later supports mocking abalibity.
When designing clean, maintainable, and object-oriented code, it's usual practice to avoid mock static methods because doing so could interfere with the project architecture.
One of the foundational principles of unit testing is that in order to use it, code must be written in a specific way that makes it testable.
This can be accomplished by using a concept known as dependency injection, or by specifying dependencies as interfaces that can be used in place of "fake implementations" during testing.
Static Utility Class
In order to mock the static method, I developed a simple utility class with two static methods, getTodayDay()
and getDayFromDate(LocalDate localDate)
.
Both methods are used to determine the day of the week. I've written two methods to demonstrate how to mock the static method without an argument and the static method with an argument.
Utility class
package in.learnjavaskills.mockitotutorial.utils;
import in.learnjavaskills.mockitotutorial.enums.WeekDays;
import java.time.LocalDate;
import java.util.Calendar;
public class Utility
{
public static WeekDays getTodayDay()
{
int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
return WeekDays.getWeekDay(day);
}
public static WeekDays getDayFromDate(LocalDate localDate)
{
int day = localDate.getDayOfWeek().getValue();
return switch (day) {
case 1, 2, 3, 4, 5, 6 -> WeekDays.getWeekDay(day+1);
case 7 -> WeekDays.SUNDAY;
default -> WeekDays.UNKNOWN;
};
}
}
WeekDays enum
package in.learnjavaskills.mockitotutorial.enums;
public enum WeekDays
{
SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THURSDAY(5),
FRIDAY(6), SATURDAY(7), UNKNOWN(0);
private int day;
WeekDays(int day)
{
this.day = day;
}
public static WeekDays getWeekDay(int day)
{
for (WeekDays weekDays : WeekDays.values())
if (weekDays.day == day)
return weekDays;
return WeekDays.UNKNOWN;
}
}
MockedStatic<T> Interface
The MockedStatic<T>
interface, which is included in the org.mockito
package, represents an active mock of a type's static methods.
The mocking only impacts the thread on which this static mock was produced, therefore using this object from another thread is not safe.
It is advised that you use the ScopedMock.close()
method to release the static mock. If the static mock is never closed, it will continue active on the current process.
Since MockedStaticc<T> extends the ScopedMock interface farther than the AutoCloseable interface, it is advised to utilize it within the try-with resource, which will be auto-closed.
Mocking the No-Argument static method
Mock the first static method, getTodayDay()
, which returns an enum of WeekDays.
To test the static mocking behavior of the MockedStatic<T> Interface, I'll use the getTodayDay() method without mocking to retrieve an actual day of the week, and then mock it inside the try-with resource scope to return the other day.
Once the scope of try-with resources has been fulfilled, we will call the getTodayDay() method again to see if the mock has been released.
package in.learnjavaskills.mockitotutorial.utils;
import in.learnjavaskills.mockitotutorial.enums.WeekDays;
import org.junit.jupiter.api.Test;
import org.mockito.BDDMockito;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.time.LocalDate;
import static org.junit.jupiter.api.Assertions.*;
class UtilityTest
{
@Test
void mockGetTodayDay()
{
// testing actual day without mocking
assertEquals(WeekDays.TUESDAY, Utility.getTodayDay());
try (MockedStatic<Utility> utilityMockStatic = Mockito.mockStatic(Utility.class))
{
// mocking the getTodayDay method to get response of the day of week as sunday instead of today day
utilityMockStatic.when(Utility :: getTodayDay)
.thenReturn(WeekDays.SUNDAY);
assertEquals(WeekDays.SUNDAY, Utility.getTodayDay());
// verify getTodayDay method invoke at least one time
utilityMockStatic.verify(Utility :: getTodayDay);
}
// testing is mock release after the try-with resource scope
assertEquals(WeekDays.TUESDAY, Utility.getTodayDay());
}
}
Mocking the Static Method with Arguments
Mocking the static method with the argument is identical to mocking the static method without the argument.
Let's first grasp the Verification Interface
before mocking the static method with the parameter.
Verification Interface
The Verification interface is a functional interface with a single abstract method, void apply()
, which throws Throwable. It's in the org.mockito
package and is used to validate the static method.
The MockedStatic<T> interface's when()
method required the Verification in the parameter and syntax given below.
<S> OngoingStubbing<S> when(Verification verification);
We utilized the method reference in the previous example of mocking the static method, but if you wish to mock the argument static method, you must implement the apply()
abstract method of the Verification interface using the lambda expression.
Program on Mocking the Static Method with Arguments
package in.learnjavaskills.mockitotutorial.utils;
import in.learnjavaskills.mockitotutorial.enums.WeekDays;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.BDDMockito;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.time.LocalDate;
import static org.junit.jupiter.api.Assertions.*;
class UtilityTest
{
@Test
void mockGetDayFromDate()
{
LocalDate localDate = LocalDate.now();
// testing getDayFromDate without mocking
assertEquals(WeekDays.TUESDAY, Utility.getDayFromDate(localDate));
// let's mock the Utility.getDayFromDate to return Sunday.
try(MockedStatic<Utility> utilityMockStatic = Mockito.mockStatic(Utility.class))
{
utilityMockStatic.when(()-> Utility.getDayFromDate(ArgumentMatchers.any()))
.thenReturn(WeekDays.SUNDAY);
assertEquals(WeekDays.SUNDAY, Utility.getDayFromDate(localDate));
// verify mock has been called
utilityMockStatic.verify( ()-> Utility.getDayFromDate(localDate));
}
// check if mock has been release by invoking getDayFromDate outside try-with scope
assertEquals(WeekDays.TUESDAY, Utility.getDayFromDate(localDate));
}
}
Conclussion
We learnt how to mock both sorts of static methods in this brief tutorial: static methods with parameters and static methods without arguments.
We recognize the MockedStatic<T> interface, as well as the parameter of the MockedStatic<T>'s when() method, i.e., the Verification Interface.
Always use MockedStatic<T> with the try-with resource, as it is critical to release the mocking by executing the ScopedMock interface's close() function.(alert-success)
Keep learning and keep growing.
(getButton) #text=(Next: Mockito Exception Throwing for Unit Testing) #icon=(link) #color=(#2339bd)