0
# Annotation-Based Testing
1
2
Mockito provides annotations to streamline test setup by automatically creating mocks, spies, and argument captors. This reduces boilerplate code and makes tests more readable.
3
4
## Core Annotations
5
6
### @Mock Annotation
7
8
Mark fields as mocks for automatic creation:
9
10
```java { .api }
11
@Target(FIELD)
12
@Retention(RUNTIME)
13
@Documented
14
public @interface Mock {
15
Answers answer() default Answers.RETURNS_DEFAULTS;
16
String name() default "";
17
Class<?>[] extraInterfaces() default {};
18
boolean serializable() default false;
19
}
20
```
21
22
**Usage Examples:**
23
24
```java
25
public class UserServiceTest {
26
@Mock
27
private UserRepository userRepository;
28
29
@Mock(name = "emailService")
30
private EmailService emailService;
31
32
@Mock(answer = Answers.RETURNS_SMART_NULLS)
33
private ConfigService configService;
34
35
@Mock(extraInterfaces = {Serializable.class, Cloneable.class})
36
private DataProcessor processor;
37
38
@Mock(serializable = true)
39
private CacheService cacheService;
40
41
@Before
42
public void setUp() {
43
MockitoAnnotations.initMocks(this);
44
}
45
}
46
```
47
48
### @Spy Annotation
49
50
Mark fields as spies for wrapping real objects:
51
52
```java { .api }
53
@Retention(RUNTIME)
54
@Target(FIELD)
55
@Documented
56
public @interface Spy { }
57
```
58
59
**Usage Examples:**
60
61
```java
62
public class ServiceTest {
63
// Spy with explicit instance
64
@Spy
65
private List<String> spyList = new ArrayList<>();
66
67
// Spy with default constructor (Mockito creates instance)
68
@Spy
69
private UserService userService;
70
71
@Before
72
public void setUp() {
73
MockitoAnnotations.initMocks(this);
74
}
75
76
@Test
77
public void testSpyBehavior() {
78
// Real method is called
79
spyList.add("item");
80
assertEquals(1, spyList.size());
81
82
// Can stub methods
83
doReturn(100).when(spyList).size();
84
assertEquals(100, spyList.size());
85
}
86
}
87
```
88
89
### @InjectMocks Annotation
90
91
Mark fields where mocks should be injected:
92
93
```java { .api }
94
@Documented
95
@Target(FIELD)
96
@Retention(RUNTIME)
97
public @interface InjectMocks { }
98
```
99
100
**Usage Examples:**
101
102
```java
103
public class UserServiceTest {
104
@Mock
105
private UserRepository repository;
106
107
@Mock
108
private EmailService emailService;
109
110
@Mock
111
private ValidationService validationService;
112
113
@InjectMocks
114
private UserService userService; // Mocks will be injected here
115
116
@Before
117
public void setUp() {
118
MockitoAnnotations.initMocks(this);
119
}
120
121
@Test
122
public void testUserCreation() {
123
User user = new User("John", "john@example.com");
124
when(repository.save(any(User.class))).thenReturn(user);
125
126
User result = userService.createUser("John", "john@example.com");
127
128
assertEquals("John", result.getName());
129
verify(emailService).sendWelcomeEmail(user);
130
}
131
}
132
```
133
134
### @Captor Annotation
135
136
Mark fields as argument captors:
137
138
```java { .api }
139
@Retention(RUNTIME)
140
@Target(FIELD)
141
@Documented
142
public @interface Captor { }
143
```
144
145
**Usage Examples:**
146
147
```java
148
public class EmailServiceTest {
149
@Mock
150
private EmailProvider emailProvider;
151
152
@Captor
153
private ArgumentCaptor<EmailMessage> messageCaptor;
154
155
@Captor
156
private ArgumentCaptor<String> stringCaptor;
157
158
@InjectMocks
159
private EmailService emailService;
160
161
@Before
162
public void setUp() {
163
MockitoAnnotations.initMocks(this);
164
}
165
166
@Test
167
public void testEmailSending() {
168
emailService.sendWelcomeEmail("user@example.com", "John");
169
170
verify(emailProvider).send(messageCaptor.capture());
171
EmailMessage capturedMessage = messageCaptor.getValue();
172
173
assertEquals("user@example.com", capturedMessage.getTo());
174
assertEquals("Welcome John!", capturedMessage.getSubject());
175
}
176
}
177
```
178
179
## Initialization
180
181
### MockitoAnnotations.initMocks()
182
183
Initialize all annotated fields:
184
185
```java { .api }
186
public class MockitoAnnotations {
187
public static void initMocks(Object testClass);
188
}
189
```
190
191
**Usage Patterns:**
192
193
```java
194
// In @Before method
195
@Before
196
public void setUp() {
197
MockitoAnnotations.initMocks(this);
198
}
199
200
// In test constructor
201
public MyTest() {
202
MockitoAnnotations.initMocks(this);
203
}
204
205
// In @BeforeEach (JUnit 5)
206
@BeforeEach
207
void setUp() {
208
MockitoAnnotations.initMocks(this);
209
}
210
```
211
212
## Dependency Injection Strategies
213
214
### Constructor Injection
215
216
Mockito tries constructor injection first (biggest constructor):
217
218
```java
219
public class UserService {
220
private final UserRepository repository;
221
private final EmailService emailService;
222
223
// Mockito will use this constructor
224
public UserService(UserRepository repository, EmailService emailService) {
225
this.repository = repository;
226
this.emailService = emailService;
227
}
228
}
229
230
public class UserServiceTest {
231
@Mock private UserRepository repository;
232
@Mock private EmailService emailService;
233
@InjectMocks private UserService userService;
234
235
// Mocks will be injected via constructor
236
}
237
```
238
239
### Setter Injection
240
241
If constructor injection fails, Mockito tries setter injection:
242
243
```java
244
public class UserService {
245
private UserRepository repository;
246
private EmailService emailService;
247
248
public void setRepository(UserRepository repository) {
249
this.repository = repository;
250
}
251
252
public void setEmailService(EmailService emailService) {
253
this.emailService = emailService;
254
}
255
}
256
```
257
258
### Field Injection
259
260
If setter injection fails, Mockito tries field injection:
261
262
```java
263
public class UserService {
264
private UserRepository repository; // Will be injected
265
private EmailService emailService; // Will be injected
266
}
267
```
268
269
## JUnit Integration
270
271
### MockitoJUnitRunner
272
273
Automatically initializes mocks without explicit setup:
274
275
```java { .api }
276
public class MockitoJUnitRunner extends Runner { }
277
```
278
279
**Usage:**
280
281
```java
282
@RunWith(MockitoJUnitRunner.class)
283
public class UserServiceTest {
284
@Mock
285
private UserRepository repository;
286
287
@InjectMocks
288
private UserService userService;
289
290
// No need for MockitoAnnotations.initMocks()
291
292
@Test
293
public void testUser() {
294
// Test implementation
295
}
296
}
297
```
298
299
### Verbose Runner
300
301
Enhanced debugging with verbose output:
302
303
```java { .api }
304
public class VerboseMockitoJUnitRunner extends MockitoJUnitRunner { }
305
```
306
307
**Usage:**
308
309
```java
310
@RunWith(VerboseMockitoJUnitRunner.class)
311
public class UserServiceTest {
312
// Provides detailed output for debugging
313
}
314
```
315
316
### MockitoRule (Alternative to Runner)
317
318
Use when you can't use MockitoJUnitRunner:
319
320
```java { .api }
321
public interface MockitoRule extends TestRule { }
322
323
public class MockitoJUnit {
324
public static MockitoRule rule();
325
}
326
```
327
328
**Usage:**
329
330
```java
331
public class UserServiceTest {
332
@Rule
333
public MockitoRule mockitoRule = MockitoJUnit.rule();
334
335
@Mock
336
private UserRepository repository;
337
338
@InjectMocks
339
private UserService userService;
340
}
341
```
342
343
## Best Practices
344
345
### Field vs Method Initialization
346
347
```java
348
// Good - field initialization for simple cases
349
@Spy
350
private List<String> list = new ArrayList<>();
351
352
// Good - method initialization for complex setup
353
@Spy
354
private ComplexService service;
355
356
@Before
357
public void setUp() {
358
service = new ComplexService(config, dependencies);
359
MockitoAnnotations.initMocks(this);
360
}
361
```
362
363
### Naming Conventions
364
365
```java
366
// Good - descriptive names
367
@Mock(name = "userRepository")
368
private UserRepository userRepository;
369
370
@Mock(name = "emailService")
371
private EmailService emailService;
372
373
// Good - match field names with dependencies
374
public class UserService {
375
private UserRepository userRepository; // Matches mock field name
376
private EmailService emailService; // Matches mock field name
377
}
378
```
379
380
### Mock Configuration
381
382
```java
383
// Good - appropriate answers for test scenarios
384
@Mock(answer = Answers.RETURNS_SMART_NULLS)
385
private ComplexService complexService;
386
387
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
388
private FluentApi fluentApi;
389
390
// Good - extra interfaces when needed
391
@Mock(extraInterfaces = {Serializable.class})
392
private DataTransferObject dto;
393
```
394
395
### Injection Best Practices
396
397
```java
398
public class ServiceTest {
399
@Mock private Dependency1 dep1;
400
@Mock private Dependency2 dep2;
401
402
@InjectMocks private Service service;
403
404
@Test
405
public void testServiceBehavior() {
406
// Configure mocks
407
when(dep1.getData()).thenReturn("data");
408
409
// Test service that uses injected mocks
410
String result = service.processData();
411
412
// Verify interactions
413
verify(dep1).getData();
414
assertEquals("processed: data", result);
415
}
416
}
417
```
418
419
## Common Pitfalls
420
421
### Initialization Order
422
423
```java
424
// WRONG - calling initMocks() in constructor of superclass
425
public class BaseTest {
426
public BaseTest() {
427
MockitoAnnotations.initMocks(this); // Subclass fields not yet initialized
428
}
429
}
430
431
// CORRECT - use @Before or test runner
432
@RunWith(MockitoJUnitRunner.class)
433
public class MyTest extends BaseTest {
434
@Mock private Service service;
435
}
436
```
437
438
### Spy Limitations
439
440
```java
441
// Mockito cannot instantiate these:
442
@Spy private InnerClass inner; // Inner classes
443
@Spy private AbstractClass abs; // Abstract classes
444
@Spy private Interface intf; // Interfaces
445
@Spy private final FinalClass fin; // Final fields
446
@Spy private static StaticClass stat; // Static fields
447
```
448
449
### Injection Failures
450
451
```java
452
// Will fail injection - no matching constructor/setter/field
453
public class Service {
454
public Service(String config, int port) { } // No default constructor
455
// No setters or matching fields
456
}
457
458
public class Test {
459
@Mock private UserRepository repo; // Type doesn't match constructor params
460
@InjectMocks private Service service; // Injection will fail silently
461
}
462
```