0
# Spying
1
2
Spy creation with type safety and immediate stubbing options for testing real objects with selective method stubbing. Essential for partial mocking scenarios where you want to test real object behavior while controlling specific methods.
3
4
## Capabilities
5
6
### Basic Spy Creation
7
8
Functions for creating spies of real objects with type safety.
9
10
```kotlin { .api }
11
/**
12
* Creates a spy of the real object using the default constructor
13
* The spy calls real methods unless they are stubbed
14
* @returns Spy instance of type T
15
*/
16
inline fun <reified T : Any> spy(): T
17
```
18
19
**Usage Examples:**
20
21
```kotlin
22
import com.nhaarman.mockitokotlin2.*
23
24
// Create spy using default constructor
25
val userServiceSpy = spy<UserService>()
26
27
// Real methods are called unless stubbed
28
val result = userServiceSpy.findUser("john123") // Calls real method
29
```
30
31
### Spy with Immediate Stubbing
32
33
Creates a spy with immediate stubbing configuration using DSL syntax.
34
35
```kotlin { .api }
36
/**
37
* Creates a spy of the real object with immediate stubbing configuration
38
* The spy calls real methods unless they are stubbed
39
* @param stubbing Lambda for configuring spy behavior immediately after creation
40
* @returns Configured spy instance of type T
41
*/
42
inline fun <reified T : Any> spy(stubbing: KStubbing<T>.(T) -> Unit): T
43
```
44
45
**Usage Examples:**
46
47
```kotlin
48
import com.nhaarman.mockitokotlin2.*
49
50
// Create spy with immediate stubbing
51
val userServiceSpy = spy<UserService> {
52
on { findUser("testUser") } doReturn testUser
53
on { isUserActive(any()) } doReturn true
54
}
55
56
// Real methods called for non-stubbed calls
57
val realUser = userServiceSpy.findUser("realUser") // Calls real method
58
val testUser = userServiceSpy.findUser("testUser") // Returns stubbed value
59
```
60
61
### Spy from Existing Instance
62
63
Creates a spy from an existing object instance.
64
65
```kotlin { .api }
66
/**
67
* Creates a spy of the provided real object instance
68
* The spy calls real methods unless they are stubbed
69
* @param value The real object instance to spy on
70
* @returns Spy wrapping the provided instance
71
*/
72
fun <T> spy(value: T): T
73
```
74
75
**Usage Examples:**
76
77
```kotlin
78
import com.nhaarman.mockitokotlin2.*
79
80
// Create spy from existing instance
81
val realUserService = UserService(userRepository, emailService)
82
val userServiceSpy = spy(realUserService)
83
84
// Spy wraps the real instance
85
val user = userServiceSpy.findUser("john123") // Delegates to real instance
86
```
87
88
### Spy from Instance with Stubbing
89
90
Creates a spy from an existing instance with immediate stubbing configuration.
91
92
```kotlin { .api }
93
/**
94
* Creates a spy of the provided real object instance with immediate stubbing
95
* The spy calls real methods unless they are stubbed
96
* @param value The real object instance to spy on
97
* @param stubbing Lambda for configuring spy behavior immediately after creation
98
* @returns Configured spy wrapping the provided instance
99
*/
100
inline fun <reified T> spy(value: T, stubbing: KStubbing<T>.(T) -> Unit): T
101
```
102
103
**Usage Examples:**
104
105
```kotlin
106
import com.nhaarman.mockitokotlin2.*
107
108
// Create configured spy from existing instance
109
val realUserService = UserService(userRepository, emailService)
110
val userServiceSpy = spy(realUserService) {
111
// Stub specific methods while keeping others real
112
on { findUser("testUser") } doReturn testUser
113
on { sendWelcomeEmail(any()) } doNothing()
114
}
115
116
// Mix of real and stubbed behavior
117
val realUser = userServiceSpy.findUser("realUser") // Calls real method
118
val testUser = userServiceSpy.findUser("testUser") // Returns stubbed value
119
userServiceSpy.sendWelcomeEmail(testUser) // Does nothing (stubbed)
120
```
121
122
## Common Spy Usage Patterns
123
124
### Partial Mocking
125
126
Spies are ideal for partial mocking where you want to test most of the real behavior but control specific methods.
127
128
```kotlin
129
import com.nhaarman.mockitokotlin2.*
130
131
@Test
132
fun testUserRegistration() {
133
// Spy on real service but stub external dependencies
134
val userServiceSpy = spy(UserService(userRepository, emailService)) {
135
// Stub external email service call
136
on { sendWelcomeEmail(any()) } doReturn true
137
// Keep all other methods real
138
}
139
140
// Test real registration logic with stubbed email
141
val result = userServiceSpy.registerUser(newUserData)
142
143
// Verify real method was called
144
verify(userServiceSpy).saveUser(any())
145
// Verify stubbed method was called
146
verify(userServiceSpy).sendWelcomeEmail(any())
147
148
assertThat(result).isNotNull()
149
}
150
```
151
152
### Method Call Verification
153
154
Verify that real methods are called with expected arguments while maintaining real behavior.
155
156
```kotlin
157
import com.nhaarman.mockitokotlin2.*
158
159
@Test
160
fun testCachingBehavior() {
161
val userServiceSpy = spy<UserService>()
162
163
// Call method multiple times
164
userServiceSpy.findUser("john123")
165
userServiceSpy.findUser("john123")
166
userServiceSpy.findUser("jane456")
167
168
// Verify caching behavior
169
verify(userServiceSpy, times(2)).findUser("john123")
170
verify(userServiceSpy, times(1)).findUser("jane456")
171
}
172
```
173
174
### Exception Testing
175
176
Stub specific methods to throw exceptions while keeping other behavior real.
177
178
```kotlin
179
import com.nhaarman.mockitokotlin2.*
180
181
@Test
182
fun testErrorHandling() {
183
val userServiceSpy = spy<UserService> {
184
// Simulate database failure for specific user
185
on { findUser("errorUser") } doThrow RuntimeException("Database error")
186
}
187
188
// Test error handling
189
assertThrows<RuntimeException> {
190
userServiceSpy.findUser("errorUser")
191
}
192
193
// Other users work normally
194
val normalUser = userServiceSpy.findUser("normalUser")
195
assertThat(normalUser).isNotNull()
196
}
197
```
198
199
### Integration Testing
200
201
Use spies to test integration between components while controlling external dependencies.
202
203
```kotlin
204
import com.nhaarman.mockitokotlin2.*
205
206
@Test
207
fun testOrderProcessing() {
208
val paymentServiceSpy = spy(PaymentService(paymentGateway)) {
209
// Stub external payment gateway
210
on { processPayment(any()) } doReturn PaymentResult.success("txn123")
211
}
212
213
val orderService = OrderService(orderRepository, paymentServiceSpy)
214
215
// Test real order processing with stubbed payment
216
val result = orderService.processOrder(testOrder)
217
218
// Verify real order processing occurred
219
assertThat(result.status).isEqualTo(OrderStatus.COMPLETED)
220
221
// Verify payment service interaction
222
verify(paymentServiceSpy).processPayment(testOrder.paymentInfo)
223
}
224
```
225
226
## Types
227
228
```kotlin { .api }
229
// From mockito-kotlin
230
class KStubbing<out T>(val mock: T)
231
232
// Standard Kotlin types
233
interface Any
234
```