0
# Annotations
1
2
Annotation-based mock initialization system with automatic dependency injection and comprehensive JUnit integration for streamlined test setup and lifecycle management.
3
4
## Capabilities
5
6
### Core Mock Annotations
7
8
Annotations for automatic mock creation and initialization.
9
10
```kotlin { .api }
11
/**
12
* Creates a mock instance
13
* @property name Optional name for the mock
14
* @property relaxed If true, unstubbed methods return default values
15
* @property relaxUnitFun If true, only Unit-returning methods are relaxed
16
*/
17
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
18
annotation class MockK(
19
val name: String = "",
20
val relaxed: Boolean = false,
21
val relaxUnitFun: Boolean = false
22
)
23
24
/**
25
* Creates a relaxed mock instance (equivalent to @MockK(relaxed = true))
26
* @property name Optional name for the mock
27
*/
28
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
29
annotation class RelaxedMockK(
30
val name: String = ""
31
)
32
33
/**
34
* Creates a spy instance
35
* @property name Optional name for the spy
36
* @property recordPrivateCalls If true, enables private call recording
37
*/
38
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
39
annotation class SpyK(
40
val name: String = "",
41
val recordPrivateCalls: Boolean = true
42
)
43
44
/**
45
* Creates a capturing slot
46
*/
47
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
48
annotation class Slot
49
```
50
51
**Usage Examples:**
52
53
```kotlin
54
class UserServiceTest {
55
@MockK
56
lateinit var userRepository: UserRepository
57
58
@RelaxedMockK
59
lateinit var logger: Logger
60
61
@SpyK
62
var emailService = EmailService()
63
64
@MockK(name = "testCache", relaxUnitFun = true)
65
lateinit var cache: CacheService
66
67
@Slot
68
lateinit var userSlot: CapturingSlot<User>
69
70
@BeforeEach
71
fun setUp() {
72
MockKAnnotations.init(this)
73
}
74
75
@Test
76
fun testUserCreation() {
77
// Mocks are automatically initialized
78
every { userRepository.save(capture(userSlot)) } returns User("123", "John")
79
80
val userService = UserService(userRepository, logger, emailService, cache)
81
userService.createUser("John", "john@example.com")
82
83
verify { userRepository.save(any()) }
84
assertEquals("John", userSlot.captured.name)
85
}
86
}
87
```
88
89
### Dependency Injection
90
91
Automatic injection of mocks into test subjects.
92
93
```kotlin { .api }
94
/**
95
* Injects mocks into the annotated property
96
* @property lookupType Strategy for finding mocks to inject
97
* @property injectImmutable If true, can inject into val properties
98
* @property overrideValues If true, overrides existing property values
99
*/
100
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
101
annotation class InjectMockKs(
102
val lookupType: InjectionLookupType = InjectionLookupType.BOTH,
103
val injectImmutable: Boolean = false,
104
val overrideValues: Boolean = false
105
)
106
107
enum class InjectionLookupType {
108
/** Inject by property name matching */
109
BY_NAME,
110
111
/** Inject by type matching */
112
BY_TYPE,
113
114
/** Try both name and type matching */
115
BOTH
116
}
117
```
118
119
**Usage Examples:**
120
121
```kotlin
122
class UserService(
123
private val userRepository: UserRepository,
124
private val emailService: EmailService,
125
private val logger: Logger
126
) {
127
fun createUser(name: String, email: String): User {
128
val user = User(generateId(), name, email)
129
userRepository.save(user)
130
emailService.sendWelcomeEmail(user)
131
logger.info("User created: ${user.id}")
132
return user
133
}
134
}
135
136
class UserServiceTest {
137
@MockK
138
lateinit var userRepository: UserRepository
139
140
@MockK
141
lateinit var emailService: EmailService
142
143
@RelaxedMockK
144
lateinit var logger: Logger
145
146
@InjectMockKs
147
lateinit var userService: UserService
148
149
@BeforeEach
150
fun setUp() {
151
MockKAnnotations.init(this)
152
// userService now has mocks injected automatically
153
}
154
155
@Test
156
fun testUserCreation() {
157
every { userRepository.save(any()) } returns User("123", "John", "john@example.com")
158
159
val result = userService.createUser("John", "john@example.com")
160
161
verify { userRepository.save(any()) }
162
verify { emailService.sendWelcomeEmail(any()) }
163
assertEquals("123", result.id)
164
}
165
}
166
```
167
168
### Additional Interface Annotation
169
170
Specify additional interfaces for mocks to implement.
171
172
```kotlin { .api }
173
/**
174
* Specifies additional interfaces for the mock to implement
175
* @property type Interface class to implement
176
*/
177
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
178
@Repeatable
179
annotation class AdditionalInterface(
180
val type: KClass<*>
181
)
182
```
183
184
**Usage Examples:**
185
186
```kotlin
187
interface Auditable {
188
fun getAuditInfo(): String
189
}
190
191
interface Serializable
192
193
class ServiceTest {
194
@MockK
195
@AdditionalInterface(Auditable::class)
196
@AdditionalInterface(Serializable::class)
197
lateinit var userService: UserService
198
199
@BeforeEach
200
fun setUp() {
201
MockKAnnotations.init(this)
202
}
203
204
@Test
205
fun testAdditionalInterfaces() {
206
// Mock now implements UserService, Auditable, and Serializable
207
every { (userService as Auditable).getAuditInfo() } returns "audit-info"
208
209
val auditInfo = (userService as Auditable).getAuditInfo()
210
assertEquals("audit-info", auditInfo)
211
212
assertTrue(userService is Serializable)
213
}
214
}
215
```
216
217
### Mock Initialization
218
219
Functions for initializing annotated mocks.
220
221
```kotlin { .api }
222
object MockKAnnotations {
223
/**
224
* Initializes properties annotated with mock annotations
225
* @param obj Objects to initialize annotations for
226
* @param overrideRecordPrivateCalls Override recordPrivateCalls setting
227
* @param relaxUnitFun Global relaxUnitFun setting
228
* @param relaxed Global relaxed setting
229
*/
230
inline fun init(
231
vararg obj: Any,
232
overrideRecordPrivateCalls: Boolean = false,
233
relaxUnitFun: Boolean = false,
234
relaxed: Boolean = false
235
)
236
}
237
```
238
239
**Usage Examples:**
240
241
```kotlin
242
class UserServiceTest {
243
@MockK
244
lateinit var userRepository: UserRepository
245
246
@RelaxedMockK
247
lateinit var logger: Logger
248
249
@SpyK
250
var emailService = EmailService()
251
252
@InjectMockKs
253
lateinit var userService: UserService
254
255
@BeforeEach
256
fun setUp() {
257
// Initialize all annotated properties
258
MockKAnnotations.init(this)
259
}
260
261
// Alternative: Initialize with global settings
262
@BeforeEach
263
fun setUpWithGlobalSettings() {
264
MockKAnnotations.init(
265
this,
266
overrideRecordPrivateCalls = true,
267
relaxUnitFun = true,
268
relaxed = false
269
)
270
}
271
272
// Initialize multiple test objects
273
@BeforeEach
274
fun setUpMultiple() {
275
val helperTest = TestHelper()
276
MockKAnnotations.init(this, helperTest)
277
}
278
}
279
```
280
281
## JUnit Integration
282
283
### JUnit 5 Extension
284
285
Automatic mock lifecycle management for JUnit 5 tests.
286
287
```kotlin { .api }
288
/**
289
* JUnit 5 extension for MockK integration
290
* Provides automatic mock initialization and cleanup
291
*/
292
class MockKExtension :
293
BeforeEachCallback,
294
AfterEachCallback,
295
ParameterResolver
296
```
297
298
**Usage Examples:**
299
300
```kotlin
301
@ExtendWith(MockKExtension::class)
302
class UserServiceTest {
303
@MockK
304
lateinit var userRepository: UserRepository
305
306
@RelaxedMockK
307
lateinit var logger: Logger
308
309
@InjectMockKs
310
lateinit var userService: UserService
311
312
// Mocks are automatically initialized before each test
313
// and cleaned up after each test
314
315
@Test
316
fun testUserCreation() {
317
every { userRepository.save(any()) } returns User("123", "John")
318
319
val result = userService.createUser("John", "john@example.com")
320
321
verify { userRepository.save(any()) }
322
assertEquals("123", result.id)
323
}
324
325
// Parameter injection (JUnit 5 only)
326
@Test
327
fun testWithInjectedMock(@MockK emailService: EmailService) {
328
every { emailService.sendEmail(any(), any()) } returns true
329
330
val result = emailService.sendEmail("test@example.com", "Hello")
331
assertTrue(result)
332
}
333
}
334
```
335
336
### JUnit 5 Configuration Annotations
337
338
Annotations for configuring MockK behavior in JUnit 5 tests.
339
340
```kotlin { .api }
341
/**
342
* Prevents calling unmockkAll after each test
343
*/
344
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
345
annotation class KeepMocks
346
347
/**
348
* Enables automatic confirmVerified calls after test execution
349
*/
350
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
351
annotation class ConfirmVerification
352
353
/**
354
* Enables automatic checkUnnecessaryStub calls after test execution
355
*/
356
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
357
annotation class CheckUnnecessaryStub
358
359
/**
360
* Disables clearAllMocks for thread safety in parallel testing
361
*/
362
@Target(AnnotationTarget.CLASS)
363
annotation class RequireParallelTesting
364
```
365
366
**Usage Examples:**
367
368
```kotlin
369
@ExtendWith(MockKExtension::class)
370
@ConfirmVerification
371
@CheckUnnecessaryStub
372
class UserServiceTest {
373
@MockK
374
lateinit var userRepository: UserRepository
375
376
@InjectMockKs
377
lateinit var userService: UserService
378
379
@Test
380
fun testUserCreation() {
381
every { userRepository.save(any()) } returns User("123", "John")
382
383
userService.createUser("John", "john@example.com")
384
385
verify { userRepository.save(any()) }
386
// confirmVerified and checkUnnecessaryStub called automatically
387
}
388
389
@Test
390
@KeepMocks
391
fun testWithPersistentMocks() {
392
// Mocks are kept after this test
393
every { userRepository.findById("123") } returns User("123", "John")
394
}
395
}
396
397
@ExtendWith(MockKExtension::class)
398
@RequireParallelTesting
399
class ParallelTest {
400
// Safe for parallel execution
401
}
402
```
403
404
### JUnit 4 Rule
405
406
MockK integration for JUnit 4 tests.
407
408
```kotlin { .api }
409
/**
410
* JUnit 4 rule for MockK integration
411
* @param obj Test object to initialize mocks for
412
* @param confirmVerification Enable automatic confirmVerified calls
413
* @param checkUnnecessaryStub Enable automatic checkUnnecessaryStub calls
414
*/
415
class MockKRule(
416
private val obj: Any,
417
private val confirmVerification: Boolean = false,
418
private val checkUnnecessaryStub: Boolean = false
419
) : TestRule
420
```
421
422
**Usage Examples:**
423
424
```kotlin
425
class UserServiceTest {
426
@MockK
427
lateinit var userRepository: UserRepository
428
429
@RelaxedMockK
430
lateinit var logger: Logger
431
432
@InjectMockKs
433
lateinit var userService: UserService
434
435
@get:Rule
436
val mockkRule = MockKRule(this)
437
438
// Alternative with verification checks
439
@get:Rule
440
val strictMockkRule = MockKRule(
441
this,
442
confirmVerification = true,
443
checkUnnecessaryStub = true
444
)
445
446
@Test
447
fun testUserCreation() {
448
every { userRepository.save(any()) } returns User("123", "John")
449
450
val result = userService.createUser("John", "john@example.com")
451
452
verify { userRepository.save(any()) }
453
assertEquals("123", result.id)
454
}
455
}
456
```
457
458
### Best Practices
459
460
Recommended patterns for using MockK annotations effectively.
461
462
```kotlin
463
// Recommended test structure
464
@ExtendWith(MockKExtension::class)
465
class UserServiceTest {
466
// Required dependencies as mocks
467
@MockK
468
lateinit var userRepository: UserRepository
469
470
@MockK
471
lateinit var emailService: EmailService
472
473
// Optional dependencies as relaxed mocks
474
@RelaxedMockK
475
lateinit var logger: Logger
476
477
@RelaxedMockK
478
lateinit var metrics: MetricsService
479
480
// Test subject with automatic injection
481
@InjectMockKs
482
lateinit var userService: UserService
483
484
// Capture slots for argument verification
485
@Slot
486
lateinit var userSlot: CapturingSlot<User>
487
488
@Slot
489
lateinit var emailSlot: CapturingSlot<String>
490
491
@Test
492
fun testCompleteUserFlow() {
493
// Setup
494
every { userRepository.save(capture(userSlot)) } returns User("123", "John")
495
every { emailService.sendWelcomeEmail(capture(emailSlot)) } returns true
496
497
// Execute
498
val result = userService.createUser("John", "john@example.com")
499
500
// Verify
501
verify { userRepository.save(any()) }
502
verify { emailService.sendWelcomeEmail("john@example.com") }
503
504
assertEquals("John", userSlot.captured.name)
505
assertEquals("john@example.com", emailSlot.captured)
506
}
507
}
508
```