0
# Enum and Method Sources
1
2
Advanced argument providers for enum constants, method-generated arguments, and field-based data sources.
3
4
## Capabilities
5
6
### @EnumSource Annotation
7
8
Provides enum constants as test arguments with flexible selection modes and filtering options.
9
10
```java { .api }
11
/**
12
* Provides enum constants as arguments to parameterized tests
13
*/
14
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
15
@Retention(RetentionPolicy.RUNTIME)
16
@Documented
17
@API(status = STABLE, since = "5.0")
18
@ArgumentsSource(EnumArgumentsProvider.class)
19
@Repeatable(EnumSources.class)
20
@interface EnumSource {
21
/**
22
* Enum class to use (defaults to first parameter type if enum)
23
*/
24
Class<? extends Enum<?>> value() default Enum.class;
25
26
/**
27
* Specific enum constant names or regex patterns
28
*/
29
String[] names() default {};
30
31
/**
32
* Selection mode for filtering enum constants
33
*/
34
Mode mode() default INCLUDE;
35
36
/**
37
* Range start for enum constants (experimental)
38
*/
39
@API(status = EXPERIMENTAL, since = "5.12")
40
String from() default "";
41
42
/**
43
* Range end for enum constants (experimental)
44
*/
45
@API(status = EXPERIMENTAL, since = "5.12")
46
String to() default "";
47
48
/**
49
* Selection mode enum
50
*/
51
enum Mode {
52
/**
53
* Include only specified names (default)
54
*/
55
INCLUDE,
56
57
/**
58
* Exclude specified names
59
*/
60
EXCLUDE,
61
62
/**
63
* Include names matching all patterns
64
*/
65
MATCH_ALL,
66
67
/**
68
* Include names matching any pattern
69
*/
70
MATCH_ANY,
71
72
/**
73
* Exclude names matching patterns
74
*/
75
MATCH_NONE
76
}
77
}
78
```
79
80
**Usage Examples:**
81
82
```java
83
import org.junit.jupiter.params.ParameterizedTest;
84
import org.junit.jupiter.params.provider.EnumSource;
85
86
enum Planet {
87
MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE
88
}
89
90
enum Status {
91
ACTIVE, INACTIVE, PENDING, SUSPENDED
92
}
93
94
class EnumSourceExamples {
95
96
// All enum constants
97
@ParameterizedTest
98
@EnumSource(Planet.class)
99
void testAllPlanets(Planet planet) {
100
assertNotNull(planet);
101
assertNotNull(planet.name());
102
}
103
104
// Inferred enum type from parameter
105
@ParameterizedTest
106
@EnumSource
107
void testInferredEnum(Status status) {
108
assertNotNull(status);
109
}
110
111
// Specific enum constants
112
@ParameterizedTest
113
@EnumSource(value = Planet.class, names = {"EARTH", "MARS", "JUPITER"})
114
void testSpecificPlanets(Planet planet) {
115
assertTrue(planet == Planet.EARTH ||
116
planet == Planet.MARS ||
117
planet == Planet.JUPITER);
118
}
119
120
// Exclude specific constants
121
@ParameterizedTest
122
@EnumSource(value = Status.class, names = {"SUSPENDED"}, mode = EnumSource.Mode.EXCLUDE)
123
void testActiveStatuses(Status status) {
124
assertNotEquals(Status.SUSPENDED, status);
125
}
126
127
// Pattern matching - include
128
@ParameterizedTest
129
@EnumSource(value = Planet.class, names = {".*US$"}, mode = EnumSource.Mode.MATCH_ANY)
130
void testPlanetsEndingWithUs(Planet planet) {
131
// VENUS, URANUS
132
assertTrue(planet.name().endsWith("US"));
133
}
134
135
// Pattern matching - exclude
136
@ParameterizedTest
137
@EnumSource(value = Planet.class, names = {"^M.*"}, mode = EnumSource.Mode.MATCH_NONE)
138
void testPlanetsNotStartingWithM(Planet planet) {
139
// All except MERCURY, MARS
140
assertFalse(planet.name().startsWith("M"));
141
}
142
143
// Multiple patterns - match all
144
@ParameterizedTest
145
@EnumSource(value = Planet.class, names = {".*R.*", ".*N.*"}, mode = EnumSource.Mode.MATCH_ALL)
146
void testPlanetsWithRAndN(Planet planet) {
147
// SATURN, URANUS
148
assertTrue(planet.name().contains("R") && planet.name().contains("N"));
149
}
150
151
// Range selection (experimental)
152
@ParameterizedTest
153
@EnumSource(value = Planet.class, from = "EARTH", to = "JUPITER")
154
void testInnerPlanets(Planet planet) {
155
// EARTH, MARS, JUPITER
156
int ordinal = planet.ordinal();
157
assertTrue(ordinal >= Planet.EARTH.ordinal() &&
158
ordinal <= Planet.JUPITER.ordinal());
159
}
160
}
161
```
162
163
### @MethodSource Annotation
164
165
Provides arguments from factory method return values with support for various return types.
166
167
```java { .api }
168
/**
169
* Provides arguments from factory method return values
170
*/
171
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
172
@Retention(RetentionPolicy.RUNTIME)
173
@Documented
174
@API(status = STABLE, since = "5.0")
175
@ArgumentsSource(MethodArgumentsProvider.class)
176
@Repeatable(MethodSources.class)
177
@interface MethodSource {
178
/**
179
* Factory method names (defaults to test method name if empty)
180
*/
181
String[] value() default "";
182
}
183
```
184
185
**Usage Examples:**
186
187
```java
188
import org.junit.jupiter.params.ParameterizedTest;
189
import org.junit.jupiter.params.provider.MethodSource;
190
import org.junit.jupiter.params.provider.Arguments;
191
import java.util.stream.Stream;
192
import java.util.*;
193
194
class MethodSourceExamples {
195
196
// Method name matches test method name
197
@ParameterizedTest
198
@MethodSource
199
void testWithNumbers(int number) {
200
assertTrue(number > 0);
201
}
202
203
static Stream<Integer> testWithNumbers() {
204
return Stream.of(1, 2, 3, 5, 8);
205
}
206
207
// Explicit method name
208
@ParameterizedTest
209
@MethodSource("stringProvider")
210
void testWithStrings(String value) {
211
assertNotNull(value);
212
assertFalse(value.isEmpty());
213
}
214
215
static Stream<String> stringProvider() {
216
return Stream.of("apple", "banana", "cherry");
217
}
218
219
// Multiple arguments using Arguments.of()
220
@ParameterizedTest
221
@MethodSource("userProvider")
222
void testWithMultipleArgs(String name, int age, boolean active) {
223
assertNotNull(name);
224
assertTrue(age >= 0);
225
}
226
227
static Stream<Arguments> userProvider() {
228
return Stream.of(
229
Arguments.of("Alice", 25, true),
230
Arguments.of("Bob", 30, false),
231
Arguments.of("Charlie", 35, true)
232
);
233
}
234
235
// Collection return type
236
@ParameterizedTest
237
@MethodSource("listProvider")
238
void testWithList(String fruit) {
239
assertNotNull(fruit);
240
}
241
242
static List<String> listProvider() {
243
return Arrays.asList("apple", "banana", "cherry");
244
}
245
246
// Array return type
247
@ParameterizedTest
248
@MethodSource("arrayProvider")
249
void testWithArray(int value) {
250
assertTrue(value > 0);
251
}
252
253
static int[] arrayProvider() {
254
return new int[]{1, 2, 3, 4, 5};
255
}
256
257
// Object array for multiple parameters
258
@ParameterizedTest
259
@MethodSource("objectArrayProvider")
260
void testWithObjectArray(String name, double price) {
261
assertNotNull(name);
262
assertTrue(price > 0);
263
}
264
265
static Object[][] objectArrayProvider() {
266
return new Object[][]{
267
{"Apple", 1.50},
268
{"Banana", 0.75},
269
{"Cherry", 2.00}
270
};
271
}
272
273
// Iterator return type
274
@ParameterizedTest
275
@MethodSource("iteratorProvider")
276
void testWithIterator(String value) {
277
assertNotNull(value);
278
}
279
280
static Iterator<String> iteratorProvider() {
281
return Arrays.asList("one", "two", "three").iterator();
282
}
283
284
// Multiple method sources
285
@ParameterizedTest
286
@MethodSource({"positiveNumbers", "negativeNumbers"})
287
void testWithMultipleSources(int number) {
288
assertNotEquals(0, number);
289
}
290
291
static Stream<Integer> positiveNumbers() {
292
return Stream.of(1, 2, 3);
293
}
294
295
static Stream<Integer> negativeNumbers() {
296
return Stream.of(-1, -2, -3);
297
}
298
299
// External class method source
300
@ParameterizedTest
301
@MethodSource("com.example.TestDataProvider#providePairs")
302
void testWithExternalSource(String key, String value) {
303
assertNotNull(key);
304
assertNotNull(value);
305
}
306
307
// Complex data structures
308
@ParameterizedTest
309
@MethodSource("complexDataProvider")
310
void testWithComplexData(Map<String, Object> data) {
311
assertNotNull(data);
312
assertFalse(data.isEmpty());
313
}
314
315
static Stream<Map<String, Object>> complexDataProvider() {
316
return Stream.of(
317
Map.of("name", "Product A", "price", 19.99, "available", true),
318
Map.of("name", "Product B", "price", 29.50, "available", false)
319
);
320
}
321
}
322
```
323
324
### @FieldSource Annotation
325
326
Provides arguments from field values (experimental feature since JUnit 5.11).
327
328
```java { .api }
329
/**
330
* Provides arguments from field values (experimental)
331
*/
332
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
333
@Retention(RetentionPolicy.RUNTIME)
334
@Documented
335
@API(status = EXPERIMENTAL, since = "5.11")
336
@ArgumentsSource(FieldArgumentsProvider.class)
337
@Repeatable(FieldSources.class)
338
@interface FieldSource {
339
/**
340
* Field names (defaults to test method name if empty)
341
*/
342
String[] value() default "";
343
}
344
```
345
346
**Usage Examples:**
347
348
```java
349
import org.junit.jupiter.params.ParameterizedTest;
350
import org.junit.jupiter.params.provider.FieldSource;
351
import org.junit.jupiter.params.provider.Arguments;
352
import java.util.function.Supplier;
353
import java.util.stream.Stream;
354
import java.util.*;
355
356
class FieldSourceExamples {
357
358
// Static field with same name as test method
359
static List<String> testWithFieldData = Arrays.asList("apple", "banana", "cherry");
360
361
@ParameterizedTest
362
@FieldSource
363
void testWithFieldData(String fruit) {
364
assertNotNull(fruit);
365
}
366
367
// Explicit field name
368
static int[] numbers = {1, 2, 3, 5, 8};
369
370
@ParameterizedTest
371
@FieldSource("numbers")
372
void testWithNumbers(int number) {
373
assertTrue(number > 0);
374
}
375
376
// Field containing Arguments
377
static List<Arguments> userTestData = Arrays.asList(
378
Arguments.of("Alice", 25, true),
379
Arguments.of("Bob", 30, false),
380
Arguments.of("Charlie", 35, true)
381
);
382
383
@ParameterizedTest
384
@FieldSource("userTestData")
385
void testWithUserData(String name, int age, boolean active) {
386
assertNotNull(name);
387
assertTrue(age >= 0);
388
}
389
390
// Supplier field for lazy evaluation
391
static Supplier<Stream<String>> lazyStringProvider = () ->
392
Stream.of("lazy1", "lazy2", "lazy3");
393
394
@ParameterizedTest
395
@FieldSource("lazyStringProvider")
396
void testWithLazyField(String value) {
397
assertNotNull(value);
398
assertTrue(value.startsWith("lazy"));
399
}
400
401
// Multiple fields
402
static List<String> fruits = Arrays.asList("apple", "banana");
403
static List<String> vegetables = Arrays.asList("carrot", "broccoli");
404
405
@ParameterizedTest
406
@FieldSource({"fruits", "vegetables"})
407
void testWithMultipleFields(String item) {
408
assertNotNull(item);
409
}
410
411
// External class field
412
@ParameterizedTest
413
@FieldSource("com.example.TestData#testValues")
414
void testWithExternalField(String value) {
415
assertNotNull(value);
416
}
417
}
418
```
419
420
### Container Annotations
421
422
Container annotations for multiple enum and method source annotations.
423
424
```java { .api }
425
/**
426
* Container annotation for multiple @EnumSource annotations
427
*/
428
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
429
@Retention(RetentionPolicy.RUNTIME)
430
@Documented
431
@API(status = STABLE, since = "5.0")
432
@interface EnumSources {
433
EnumSource[] value();
434
}
435
436
/**
437
* Container annotation for multiple @MethodSource annotations
438
*/
439
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
440
@Retention(RetentionPolicy.RUNTIME)
441
@Documented
442
@API(status = STABLE, since = "5.0")
443
@interface MethodSources {
444
MethodSource[] value();
445
}
446
447
/**
448
* Container annotation for multiple @FieldSource annotations
449
*/
450
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
451
@Retention(RetentionPolicy.RUNTIME)
452
@Documented
453
@API(status = EXPERIMENTAL, since = "5.11")
454
@interface FieldSources {
455
FieldSource[] value();
456
}
457
```
458
459
### Advanced Patterns
460
461
**Complex Method Source Patterns:**
462
463
```java
464
class AdvancedMethodSourceExamples {
465
466
// Parameterized test with test case names
467
@ParameterizedTest(name = "Test case: {0}")
468
@MethodSource("namedTestCases")
469
void testWithNamedCases(String testCase, int input, int expected) {
470
// Test implementation using testCase description
471
assertNotNull(testCase);
472
assertTrue(input >= 0);
473
assertTrue(expected >= 0);
474
}
475
476
static Stream<Arguments> namedTestCases() {
477
return Stream.of(
478
Arguments.of("Square root of 4", 4, 2),
479
Arguments.of("Square root of 9", 9, 3),
480
Arguments.of("Square root of 16", 16, 4)
481
);
482
}
483
484
// Dynamic data generation
485
@ParameterizedTest
486
@MethodSource("dynamicDataProvider")
487
void testWithDynamicData(int value) {
488
assertTrue(value > 0);
489
}
490
491
static Stream<Integer> dynamicDataProvider() {
492
return Stream.iterate(1, n -> n < 100, n -> n * 2);
493
}
494
495
// Combining different data sources
496
@ParameterizedTest
497
@MethodSource("combinedDataProvider")
498
void testWithCombinedData(String type, Object value) {
499
assertNotNull(type);
500
assertNotNull(value);
501
}
502
503
static Stream<Arguments> combinedDataProvider() {
504
return Stream.concat(
505
Stream.of("string").map(s -> Arguments.of("String", s)),
506
Stream.of(42).map(i -> Arguments.of("Integer", i))
507
);
508
}
509
}
510
```
511
512
These advanced source types provide powerful capabilities for data-driven testing, enabling complex test scenarios with enum-based logic, dynamic data generation, and external data sources.