How to mock static method of Mockito
In actual work, we often encounter situations where we need to mock static methods. In the era of mockito, we need to use powmock to achieve it.
After mockito evolved to version 3.4.0, it also began to support the static method mock (mainly through the mockito-inline package).
This is the brief introduction, let’s get to the topic below.
1. First make sure that the pom file is in
The version of the mockito-related jar package (the version I use here is 3.7.7), as follows:
<dependency> <groupId></groupId> <artifactId>mockito-core</artifactId> <version>3.7.7</version> <scope>test</scope> </dependency> <dependency> <groupId></groupId> <artifactId>mockito-inline</artifactId> <version>3.7.7</version> <scope>test</scope> </dependency> <dependency> <groupId></groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>3.7.7</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency>
2. How to use
(Class mockClass),as follows:
// Here static methods are provided in DateUtilMockedStatic<DateUtil> dateUtil = mockStatic();
Example:
import static ; @RunWith() public class AlphaServiceTest { @Test public void testHttp() { ... MockedStatic<HTTPClient> httpClient = mockStatic(); (() -> ("xxx/zzz/ccc", "hello")).thenReturn("success"); ... // closure (); }
This is basically OK.
The only thing to note is (), this problem will be explained in "3. Others" in "Error prompt static mocking is already registered in the current thread To create a new mock, the existing static mock registration must be deregistered")
3. Others
If mockito-inline is not introduced into the project, the following error message will appear:
:
The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static mocksMockito's inline mock maker supports static mocks based on the Instrumentation API.
You can simply enable this mock mode, by placing the 'mockito-inline' artifact where you are currently using 'mockito-core'.
Note that Mockito's inline mock maker is not supported on Android.at .testSaveClinicalFreeSuccess1(:86)
at .invoke0(Native Method)
at (:62)
at (:43)
at (:498)
at $(:50)
at (:12)
at (:47)
at (:17)
at .(:74)
at .(:84)
at .(:75)
at .(:86)
at .(:84)
at (:325)
at .junit4.(:251)
at .junit4.(:97)
at $(:290)
at $(:71)
at (:288)
at $000(:58)
at $(:268)
at .(:61)
at .(:70)
at (:363)
at .junit4.(:190)
at (:137)
at .junit4.(:68)
at $(:33)
at (:230)
at (:58)
Error message
static mocking is already registered in the current thread To create a new mock, the existing static mock registration must be deregistered
When multiple unit tests use the same static mock object, and no close is performed after use. At this time, if these unit tests are executed together, the first unit test occupies the static mock object, and the second unit test has no way to occupy it.
If this happens, the solution is also very simple, which is to close the static mock object, as follows:
import static ; @RunWith() public class AlphaServiceTest { @Test public void testHttp1() { ... MockedStatic<HTTPClient> httpClient = mockStatic(); (() -> ("xxx/zzz/ccc", "hello")).thenReturn("success"); ... (); } @Test public void testHttp2() { ... MockedStatic<HTTPClient> httpClient = mockStatic(); (() -> ("xxx/zzz/ccc", "hello")).thenReturn("success"); ... (); } @Test public void testHttp3() { ... MockedStatic<HTTPClient> httpClient = mockStatic(); (() -> ("xxx/zzz/ccc", "hello")).thenReturn("success"); ... (); }
If you use mockStatic() in many of your unit tests and think that writing mockStatic()…close() is very inefficient, you can use the following method:
import static ; @RunWith() public class AlphaServiceTest { private MockedStatic<HttpClietn> httpClient; // Before each unit test is started, execute this method first (@Before was replaced with @BeforeEach in the higher version) @Before public void setUp() { = mockStatic(); } // After each unit test is executed, execute this method (@After is replaced with @AfterEach in the higher version) @After public void teardown() { (); } @Test public void testHttp1() { ... (() -> ("xxx/zzz/ccc", "hello")).thenReturn("success"); ... } @Test public void testHttp2() { ... (() -> ("xxx/zzz/ccc", "hello")).thenReturn("success"); ... } @Test public void testHttp3() { ... (() -> ("xxx/zzz/ccc", "hello")).thenReturn("success"); ... }
This makes it much more refreshing ~ :)
Summarize
The above is personal experience. I hope you can give you a reference and I hope you can support me more.