0
# Static and Construction Mocking
1
2
This section covers advanced mocking capabilities introduced in Mockito 3.4+ for mocking static methods and object construction.
3
4
## Static Method Mocking
5
6
### MockedStatic Interface
7
8
Mock static methods within a controlled scope.
9
10
```java { .api }
11
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock)
12
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock, String name)
13
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock, Answer defaultAnswer)
14
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock, MockSettings settings)
15
16
interface MockedStatic<T> extends AutoCloseable {
17
<S> OngoingStubbing<S> when(Verification verification);
18
<S> void verify(Verification verification);
19
void verify(Verification verification, VerificationMode mode);
20
void verifyNoMoreInteractions();
21
void verifyNoInteractions();
22
void clearInvocations();
23
void close();
24
void closeOnDemand();
25
boolean isClosed();
26
}
27
```
28
29
**Usage Examples:**
30
31
```java
32
// Basic static mocking
33
@Test
34
void testStaticMethod() {
35
try (MockedStatic<Math> mockedMath = mockStatic(Math.class)) {
36
// Stub static method
37
mockedMath.when(() -> Math.max(1, 2)).thenReturn(5);
38
39
// Use static method
40
int result = Math.max(1, 2);
41
assertEquals(5, result);
42
43
// Verify static method call
44
mockedMath.verify(() -> Math.max(1, 2));
45
}
46
// Static mock automatically closed
47
}
48
49
// Static mocking with argument matchers
50
@Test
51
void testStaticWithMatchers() {
52
try (MockedStatic<Files> mockedFiles = mockStatic(Files.class)) {
53
mockedFiles.when(() -> Files.exists(any(Path.class)))
54
.thenReturn(true);
55
56
boolean exists = Files.exists(Paths.get("/any/path"));
57
assertTrue(exists);
58
59
mockedFiles.verify(() -> Files.exists(any(Path.class)));
60
}
61
}
62
```
63
64
### Partial Static Mocking
65
66
Mock only specific static methods while keeping others unchanged.
67
68
```java
69
@Test
70
void testPartialStaticMocking() {
71
try (MockedStatic<StringUtils> mockedUtils = mockStatic(StringUtils.class, CALLS_REAL_METHODS)) {
72
// Only mock specific method
73
mockedUtils.when(() -> StringUtils.isEmpty("test")).thenReturn(true);
74
75
// This calls the real method
76
String result = StringUtils.capitalize("hello");
77
assertEquals("Hello", result);
78
79
// This calls the mocked method
80
boolean isEmpty = StringUtils.isEmpty("test");
81
assertTrue(isEmpty);
82
}
83
}
84
```
85
86
## Construction Mocking
87
88
### MockedConstruction Interface
89
90
Mock object construction and initialization.
91
92
```java { .api }
93
public static <T> MockedConstruction<T> mockConstruction(Class<T> classToMock)
94
public static <T> MockedConstruction<T> mockConstruction(Class<T> classToMock, Function<Context, MockSettings> settingsFactory)
95
public static <T> MockedConstruction<T> mockConstruction(Class<T> classToMock, MockInitializer<T> mockInitializer)
96
public static <T> MockedConstruction<T> mockConstruction(Class<T> classToMock, Function<Context, MockSettings> settingsFactory, MockInitializer<T> mockInitializer)
97
98
interface MockedConstruction<T> extends AutoCloseable {
99
List<T> constructed();
100
void close();
101
boolean isClosed();
102
103
interface Context {
104
int getCount();
105
Class<?> getConstructedType();
106
List<Class<?>> getParameterTypes();
107
List<Object> getArguments();
108
}
109
110
interface MockInitializer<T> {
111
void prepare(T mock, Context context) throws Throwable;
112
}
113
}
114
```
115
116
**Usage Examples:**
117
118
```java
119
// Basic construction mocking
120
@Test
121
void testConstructionMocking() {
122
try (MockedConstruction<EmailService> mockedConstruction =
123
mockConstruction(EmailService.class)) {
124
125
// Create objects - they will be mocked
126
EmailService service1 = new EmailService("config1");
127
EmailService service2 = new EmailService("config2");
128
129
// Get constructed mocks
130
List<EmailService> constructed = mockedConstruction.constructed();
131
assertEquals(2, constructed.size());
132
133
// Configure behavior
134
when(service1.sendEmail(any())).thenReturn(true);
135
when(service2.sendEmail(any())).thenReturn(false);
136
137
// Test behavior
138
assertTrue(service1.sendEmail("test"));
139
assertFalse(service2.sendEmail("test"));
140
}
141
}
142
143
// Construction mocking with initialization
144
@Test
145
void testConstructionWithInitializer() {
146
try (MockedConstruction<DatabaseConnection> mockedConstruction =
147
mockConstruction(DatabaseConnection.class, (mock, context) -> {
148
// Initialize each constructed mock
149
when(mock.isConnected()).thenReturn(true);
150
when(mock.getUrl()).thenReturn("mocked-url");
151
})) {
152
153
DatabaseConnection conn1 = new DatabaseConnection("real-url");
154
DatabaseConnection conn2 = new DatabaseConnection("another-url");
155
156
// Both connections have the same mocked behavior
157
assertTrue(conn1.isConnected());
158
assertTrue(conn2.isConnected());
159
assertEquals("mocked-url", conn1.getUrl());
160
assertEquals("mocked-url", conn2.getUrl());
161
}
162
}
163
```
164
165
### Advanced Construction Scenarios
166
167
Context-aware construction mocking with different behaviors.
168
169
```java
170
@Test
171
void testContextAwareConstruction() {
172
try (MockedConstruction<Logger> mockedConstruction =
173
mockConstruction(Logger.class,
174
context -> withSettings().name("logger-" + context.getCount()),
175
(mock, context) -> {
176
String loggerName = "Logger#" + context.getCount();
177
when(mock.getName()).thenReturn(loggerName);
178
179
// Different behavior based on constructor arguments
180
if (context.getArguments().contains("DEBUG")) {
181
when(mock.isDebugEnabled()).thenReturn(true);
182
} else {
183
when(mock.isDebugEnabled()).thenReturn(false);
184
}
185
})) {
186
187
Logger logger1 = new Logger("INFO");
188
Logger logger2 = new Logger("DEBUG");
189
190
assertEquals("Logger#1", logger1.getName());
191
assertEquals("Logger#2", logger2.getName());
192
assertFalse(logger1.isDebugEnabled());
193
assertTrue(logger2.isDebugEnabled());
194
}
195
}
196
```
197
198
## Combining Static and Construction Mocking
199
200
### Complex Mocking Scenarios
201
202
Combine different mocking approaches for comprehensive testing.
203
204
```java
205
@Test
206
void testCombinedMocking() {
207
try (MockedStatic<FileUtils> mockedFileUtils = mockStatic(FileUtils.class);
208
MockedConstruction<FileReader> mockedConstruction =
209
mockConstruction(FileReader.class, (mock, context) -> {
210
when(mock.read()).thenReturn("mocked content");
211
})) {
212
213
// Mock static utility
214
mockedFileUtils.when(() -> FileUtils.exists("test.txt"))
215
.thenReturn(true);
216
217
// Code under test
218
FileProcessor processor = new FileProcessor();
219
String result = processor.processFile("test.txt");
220
221
// Verify both static and construction calls
222
mockedFileUtils.verify(() -> FileUtils.exists("test.txt"));
223
assertEquals(1, mockedConstruction.constructed().size());
224
225
FileReader constructedReader = mockedConstruction.constructed().get(0);
226
verify(constructedReader).read();
227
}
228
}
229
```
230
231
## Best Practices and Limitations
232
233
### Resource Management
234
235
Always use try-with-resources for automatic cleanup.
236
237
```java
238
// CORRECT - automatic cleanup
239
@Test
240
void testWithTryWithResources() {
241
try (MockedStatic<System> mockedSystem = mockStatic(System.class)) {
242
mockedSystem.when(() -> System.currentTimeMillis()).thenReturn(123456L);
243
// Test code
244
} // Automatically closed
245
}
246
247
// INCORRECT - manual cleanup required
248
@Test
249
void testWithManualCleanup() {
250
MockedStatic<System> mockedSystem = mockStatic(System.class);
251
try {
252
mockedSystem.when(() -> System.currentTimeMillis()).thenReturn(123456L);
253
// Test code
254
} finally {
255
mockedSystem.close(); // Must remember to close
256
}
257
}
258
```
259
260
### Thread Safety Considerations
261
262
Static mocks are not thread-safe and should be used carefully in parallel tests.
263
264
```java
265
// Isolate static mocking in test methods
266
class ThreadSafeStaticTest {
267
@Test
268
void test1() {
269
try (MockedStatic<Math> mock = mockStatic(Math.class)) {
270
// Isolated static mock
271
}
272
}
273
274
@Test
275
void test2() {
276
try (MockedStatic<Math> mock = mockStatic(Math.class)) {
277
// Separate static mock instance
278
}
279
}
280
}
281
```
282
283
### Performance Considerations
284
285
Static and construction mocking have performance overhead.
286
287
```java
288
// Use sparingly and scope appropriately
289
@Test
290
void testPerformanceAware() {
291
// Scope static mock to minimum necessary
292
String result;
293
try (MockedStatic<ExpensiveUtil> mock = mockStatic(ExpensiveUtil.class)) {
294
mock.when(() -> ExpensiveUtil.compute(any())).thenReturn("cached");
295
result = ExpensiveUtil.compute("input");
296
}
297
298
// Continue test without static mock overhead
299
assertEquals("cached", result);
300
}
301
```
302
303
### Limitations and Alternatives
304
305
Understanding when static/construction mocking isn't the best solution.
306
307
```java
308
// Instead of mocking static utilities
309
class AvoidStaticMocking {
310
// AVOID if possible
311
@Test
312
void testWithStaticMocking() {
313
try (MockedStatic<UUID> mock = mockStatic(UUID.class)) {
314
mock.when(UUID::randomUUID).thenReturn(fixedUuid);
315
// Test
316
}
317
}
318
319
// PREFER dependency injection
320
@Test
321
void testWithDependencyInjection() {
322
UuidGenerator mockGenerator = mock(UuidGenerator.class);
323
when(mockGenerator.generate()).thenReturn(fixedUuid);
324
325
MyService service = new MyService(mockGenerator);
326
// Test
327
}
328
}
329
```