0
# Argument Matching
1
2
Argument matchers provide flexible matching for method arguments during stubbing and verification. They allow you to specify patterns instead of exact values.
3
4
## Basic Matchers
5
6
### Any Matchers
7
8
```java { .api }
9
public static <T> T any();
10
public static <T> T any(Class<T> clazz);
11
public static <T> T anyObject(); // Deprecated, use any()
12
```
13
14
**Usage Examples:**
15
16
```java
17
// Match any object
18
when(mock.process(any())).thenReturn("result");
19
verify(mock).process(any());
20
21
// Match any object of specific type
22
when(mock.handle(any(String.class))).thenReturn(true);
23
when(mock.save(any(User.class))).thenReturn(user);
24
25
// Verify with type-specific matcher
26
verify(userService).save(any(User.class));
27
```
28
29
### Equality Matchers
30
31
```java { .api }
32
public static <T> T eq(T value);
33
public static <T> T same(T value);
34
public static <T> T refEq(T value, String... excludeFields);
35
```
36
37
**Usage Examples:**
38
39
```java
40
// Exact equality match
41
when(mock.get(eq("key"))).thenReturn("value");
42
verify(mock).process(eq(123));
43
44
// Same reference match
45
User user = new User();
46
when(mock.process(same(user))).thenReturn("processed");
47
48
// Reference equality with excluded fields
49
User expectedUser = new User("John", "john@example.com");
50
verify(userService).save(refEq(expectedUser, "id", "createdAt"));
51
```
52
53
### Null Matchers
54
55
```java { .api }
56
public static <T> T isNull();
57
public static <T> T isNotNull();
58
public static <T> T notNull(); // Deprecated, use isNotNull()
59
```
60
61
**Usage Examples:**
62
63
```java
64
// Match null values
65
when(service.process(isNull())).thenThrow(IllegalArgumentException.class);
66
67
// Match non-null values
68
when(service.process(isNotNull())).thenReturn("processed");
69
70
// Verification
71
verify(service).handle(isNull());
72
verify(service).save(isNotNull());
73
```
74
75
## String Matchers
76
77
```java { .api }
78
public static String anyString();
79
public static String contains(String substring);
80
public static String matches(String regex);
81
public static String endsWith(String suffix);
82
public static String startsWith(String prefix);
83
```
84
85
**Usage Examples:**
86
87
```java
88
// Any string
89
when(service.process(anyString())).thenReturn("default");
90
91
// String contains substring
92
when(service.findByName(contains("John"))).thenReturn(users);
93
verify(logger).log(contains("ERROR"));
94
95
// String matches regex
96
when(service.validate(matches("\\d{3}-\\d{2}-\\d{4}"))).thenReturn(true);
97
98
// String starts/ends with
99
when(service.getByPrefix(startsWith("user_"))).thenReturn(userData);
100
when(service.getByExtension(endsWith(".txt"))).thenReturn(textFiles);
101
```
102
103
## Numeric Matchers
104
105
```java { .api }
106
public static byte anyByte();
107
public static short anyShort();
108
public static int anyInt();
109
public static long anyLong();
110
public static float anyFloat();
111
public static double anyDouble();
112
public static boolean anyBoolean();
113
public static char anyChar();
114
```
115
116
**Usage Examples:**
117
118
```java
119
// Numeric type matchers
120
when(calculator.add(anyInt(), anyInt())).thenReturn(42);
121
when(service.processRate(anyDouble())).thenReturn(true);
122
when(service.isActive(anyBoolean())).thenReturn("status");
123
124
// Verification
125
verify(calculator).multiply(anyFloat(), anyFloat());
126
verify(service).setAge(anyByte());
127
```
128
129
## Collection Matchers
130
131
```java { .api }
132
public static <T> Collection<T> anyCollection();
133
public static <T> Collection<T> anyCollectionOf(Class<T> clazz);
134
public static <T> List<T> anyList();
135
public static <T> List<T> anyListOf(Class<T> clazz);
136
public static <T> Set<T> anySet();
137
public static <T> Set<T> anySetOf(Class<T> clazz);
138
public static <K, V> Map<K, V> anyMap();
139
public static <K, V> Map<K, V> anyMapOf(Class<K> keyClazz, Class<V> valueClazz);
140
```
141
142
**Usage Examples:**
143
144
```java
145
// Generic collection matchers
146
when(service.process(anyList())).thenReturn("processed");
147
when(service.save(anyCollection())).thenReturn(true);
148
149
// Type-specific collection matchers
150
when(service.processUsers(anyListOf(User.class))).thenReturn(results);
151
when(service.processSettings(anyMapOf(String.class, Object.class))).thenReturn(config);
152
153
// Verification
154
verify(service).updateUsers(anySetOf(User.class));
155
verify(cache).putAll(anyMap());
156
```
157
158
## Advanced Matchers
159
160
### Additional Matchers
161
162
```java { .api }
163
public class AdditionalMatchers {
164
public static <T> T not(T value);
165
public static <T> T or(T left, T right);
166
public static <T> T and(T left, T right);
167
public static <T extends Comparable<T>> T geq(T value);
168
public static <T extends Comparable<T>> T leq(T value);
169
public static <T extends Comparable<T>> T gt(T value);
170
public static <T extends Comparable<T>> T lt(T value);
171
public static <T extends Comparable<T>> T cmpEq(T value);
172
public static <T> T[] aryEq(T[] array);
173
public static String find(String regex);
174
}
175
```
176
177
**Usage Examples:**
178
179
```java
180
// Logical matchers
181
when(service.process(not(eq("invalid")))).thenReturn("valid");
182
when(service.handle(or(eq("a"), eq("b")))).thenReturn(true);
183
when(service.validate(and(startsWith("user"), endsWith("@domain.com")))).thenReturn(true);
184
185
// Comparison matchers
186
when(service.processAge(gt(18))).thenReturn("adult");
187
when(service.processScore(geq(90))).thenReturn("excellent");
188
when(service.processQuantity(lt(100))).thenReturn("available");
189
190
// Array equality
191
String[] expectedArray = {"a", "b", "c"};
192
verify(service).processArray(aryEq(expectedArray));
193
194
// Regex find in string
195
verify(logger).log(find("ERROR.*database"));
196
```
197
198
## Custom Matchers
199
200
### Hamcrest Integration
201
202
```java { .api }
203
public static <T> T argThat(Matcher<T> matcher);
204
public static boolean booleanThat(Matcher<Boolean> matcher);
205
public static byte byteThat(Matcher<Byte> matcher);
206
public static char charThat(Matcher<Character> matcher);
207
public static double doubleThat(Matcher<Double> matcher);
208
public static float floatThat(Matcher<Float> matcher);
209
public static int intThat(Matcher<Integer> matcher);
210
public static long longThat(Matcher<Long> matcher);
211
public static short shortThat(Matcher<Short> matcher);
212
```
213
214
**Usage Examples:**
215
216
```java
217
// Hamcrest matchers
218
when(service.process(argThat(hasProperty("name", equalTo("John"))))).thenReturn(user);
219
when(service.calculate(intThat(greaterThan(0)))).thenReturn(result);
220
221
// Custom Hamcrest matcher
222
verify(service).save(argThat(allOf(
223
hasProperty("name", notNullValue()),
224
hasProperty("age", greaterThan(0))
225
)));
226
```
227
228
### Lambda Matchers (Java 8+)
229
230
```java
231
// Custom logic with lambda
232
when(service.process(argThat(user -> user.getAge() > 18))).thenReturn("adult");
233
234
// Complex validation
235
verify(service).save(argThat(user ->
236
user.getName() != null &&
237
user.getEmail().contains("@") &&
238
user.getAge() >= 18
239
));
240
```
241
242
### Custom ArgumentMatcher
243
244
```java { .api }
245
public interface ArgumentMatcher<T> {
246
boolean matches(T argument);
247
}
248
```
249
250
**Usage Example:**
251
252
```java
253
class IsValidEmail implements ArgumentMatcher<String> {
254
public boolean matches(String email) {
255
return email != null && email.contains("@") && email.contains(".");
256
}
257
}
258
259
// Usage
260
when(service.sendEmail(argThat(new IsValidEmail()))).thenReturn(true);
261
```
262
263
## Matcher Best Practices
264
265
### Mixing Matchers and Exact Values
266
267
**Important Rule:** If you use any matcher for one argument, you must use matchers for all arguments:
268
269
```java
270
// WRONG - mixing matchers with exact values
271
verify(mock).someMethod(anyInt(), "exact string");
272
273
// CORRECT - use matchers for all arguments
274
verify(mock).someMethod(anyInt(), eq("exact string"));
275
```
276
277
### Appropriate Matcher Selection
278
279
```java
280
// Good - specific when it matters
281
verify(service).processUser(eq("john123"));
282
283
// Good - flexible when appropriate
284
verify(service).log(anyString());
285
286
// Avoid - too specific when flexibility is better
287
verify(service).log(eq("Processing user john123 at 2023-10-01 10:30:15"));
288
289
// Better - focus on important parts
290
verify(service).log(contains("Processing user john123"));
291
```
292
293
### Performance Considerations
294
295
```java
296
// Good - simple matchers are faster
297
verify(service).process(anyString());
298
299
// Consider performance for complex matchers
300
verify(service).process(argThat(data -> {
301
// Complex computation here
302
return expensiveValidation(data);
303
}));
304
```
305
306
### Readable Test Code
307
308
```java
309
// Good - clear intent
310
verify(emailService).sendEmail(
311
eq("user@example.com"),
312
contains("Welcome"),
313
any(EmailOptions.class)
314
);
315
316
// Avoid - unclear matchers
317
verify(service).process(argThat(x -> x.toString().length() > 5));
318
319
// Better - descriptive matcher
320
verify(service).process(argThat(hasMinimumLength(5)));
321
```
322
323
## Common Matcher Errors
324
325
### InvalidUseOfMatchersException
326
327
```java
328
// WRONG - mixing matchers and values
329
verify(mock).method(anyString(), "value");
330
331
// CORRECT
332
verify(mock).method(anyString(), eq("value"));
333
```
334
335
### Null Pointer with Matchers
336
337
```java
338
// Potentially problematic
339
String nullString = null;
340
when(service.process(eq(nullString))).thenReturn("result");
341
342
// Better
343
when(service.process(isNull())).thenReturn("result");
344
```
345
346
### Overuse of any()
347
348
```java
349
// Avoid - loses test value
350
verify(service).process(any(), any(), any());
351
352
// Better - be specific where it matters
353
verify(service).process(eq("important"), any(), anyInt());
354
```