JUnit Jupiter Migration Support provides support for JUnit 4 rules within JUnit Jupiter, enabling legacy test infrastructure to work with JUnit 5.
npx @tessl/cli install tessl/maven-org-junit-jupiter--junit-jupiter-migrationsupport@5.12.00
# JUnit Jupiter Migration Support
1
2
JUnit Jupiter Migration Support provides support for JUnit 4 rules within JUnit Jupiter, enabling legacy test infrastructure to work with JUnit 5. This module facilitates the migration of large JUnit 4 codebases by allowing existing rules to continue working unchanged within JUnit Jupiter test classes.
3
4
## Package Information
5
6
- **Package Name**: junit-jupiter-migrationsupport
7
- **Package Type**: maven
8
- **Language**: Java
9
- **Group ID**: org.junit.jupiter
10
- **Version**: 5.12.2
11
- **Installation**: Add Maven dependency:
12
13
```xml
14
<dependency>
15
<groupId>org.junit.jupiter</groupId>
16
<artifactId>junit-jupiter-migrationsupport</artifactId>
17
<version>5.12.2</version>
18
<scope>test</scope>
19
</dependency>
20
```
21
22
Gradle:
23
24
```gradle
25
testImplementation 'org.junit.jupiter:junit-jupiter-migrationsupport:5.12.2'
26
```
27
28
## Core Imports
29
30
```java
31
// Main annotations for enabling migration support
32
import org.junit.jupiter.migrationsupport.EnableJUnit4MigrationSupport;
33
import org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport;
34
35
// Core extension classes (STABLE API)
36
import org.junit.jupiter.migrationsupport.rules.ExternalResourceSupport;
37
import org.junit.jupiter.migrationsupport.rules.VerifierSupport;
38
import org.junit.jupiter.migrationsupport.rules.ExpectedExceptionSupport;
39
import org.junit.jupiter.migrationsupport.conditions.IgnoreCondition;
40
41
// Advanced adapter classes (INTERNAL API - for advanced usage)
42
import org.junit.jupiter.migrationsupport.rules.adapter.GenericBeforeAndAfterAdvice;
43
import org.junit.jupiter.migrationsupport.rules.adapter.AbstractTestRuleAdapter;
44
import org.junit.jupiter.migrationsupport.rules.adapter.ExternalResourceAdapter;
45
import org.junit.jupiter.migrationsupport.rules.adapter.VerifierAdapter;
46
import org.junit.jupiter.migrationsupport.rules.adapter.ExpectedExceptionAdapter;
47
48
// Rule member classes (INTERNAL API - for advanced usage)
49
import org.junit.jupiter.migrationsupport.rules.member.TestRuleAnnotatedMember;
50
import org.junit.jupiter.migrationsupport.rules.member.TestRuleAnnotatedField;
51
import org.junit.jupiter.migrationsupport.rules.member.TestRuleAnnotatedMethod;
52
```
53
54
## Basic Usage
55
56
### Enable Full Migration Support
57
58
```java
59
import org.junit.jupiter.migrationsupport.EnableJUnit4MigrationSupport;
60
import org.junit.jupiter.api.Test;
61
import org.junit.Rule;
62
import org.junit.rules.TemporaryFolder;
63
64
@EnableJUnit4MigrationSupport
65
public class MyMigratedTest {
66
67
@Rule
68
public TemporaryFolder tempFolder = new TemporaryFolder();
69
70
@Test
71
public void testWithRule() {
72
// Your existing JUnit 4 test code using tempFolder rule
73
// continues to work unchanged
74
}
75
}
76
```
77
78
### Enable Selective Migration Support
79
80
```java
81
import org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport;
82
import org.junit.jupiter.api.Test;
83
import org.junit.Rule;
84
import org.junit.rules.TemporaryFolder;
85
86
@EnableRuleMigrationSupport
87
public class MySelectiveTest {
88
89
@Rule
90
public TemporaryFolder tempFolder = new TemporaryFolder();
91
92
@Test
93
public void testWithRule() {
94
// JUnit 4 rules work, but @Ignore annotation support not enabled
95
}
96
}
97
```
98
99
## Architecture
100
101
JUnit Jupiter Migration Support is built around several key components:
102
103
- **Migration Annotations**: Class-level annotations that enable rule support for test classes
104
- **Extension Classes**: JUnit Jupiter extensions that handle rule lifecycle integration (STABLE API)
105
- **Adapter System**: Internal adapter pattern that converts JUnit 4 rules into JUnit Jupiter extension callbacks
106
- **Member Detection**: Discovers @Rule-annotated fields and methods in test classes
107
- **Condition Support**: Enables JUnit 4's @Ignore annotation functionality
108
109
The module exports 5 packages:
110
- `org.junit.jupiter.migrationsupport` - Core annotations
111
- `org.junit.jupiter.migrationsupport.conditions` - Condition support
112
- `org.junit.jupiter.migrationsupport.rules` - Rule support extensions
113
- `org.junit.jupiter.migrationsupport.rules.adapter` - Internal adapter classes
114
- `org.junit.jupiter.migrationsupport.rules.member` - Internal member classes
115
116
The module supports both @Rule-annotated fields and methods, maintaining backward compatibility with existing JUnit 4 test infrastructure.
117
118
## Capabilities
119
120
### Full Migration Support
121
122
Enables complete JUnit 4 migration support including all rule types and @Ignore annotation support.
123
124
```java { .api }
125
/**
126
* Class-level annotation that enables all JUnit 4 migration support within JUnit Jupiter.
127
* This composed annotation registers all extensions supported by @EnableRuleMigrationSupport
128
* and provides support for JUnit 4's @Ignore annotation.
129
*
130
* API Status: STABLE (since 5.7)
131
* Since: 5.4
132
*/
133
@Target(ElementType.TYPE)
134
@Retention(RetentionPolicy.RUNTIME)
135
@EnableRuleMigrationSupport
136
@ExtendWith(IgnoreCondition.class)
137
public @interface EnableJUnit4MigrationSupport {
138
}
139
```
140
141
### Rule Migration Support
142
143
Enables native JUnit 4 rule support for Verifier, ExternalResource, and ExpectedException rules.
144
145
```java { .api }
146
/**
147
* Class-level annotation that enables native JUnit 4 rule support within JUnit Jupiter.
148
* Supports rules of type Verifier, ExternalResource, and ExpectedException.
149
*
150
* API Status: STABLE (since 5.7)
151
* Since: 5.0
152
*/
153
@Target(ElementType.TYPE)
154
@Retention(RetentionPolicy.RUNTIME)
155
@ExtendWith(ExternalResourceSupport.class)
156
@ExtendWith(VerifierSupport.class)
157
@ExtendWith(ExpectedExceptionSupport.class)
158
public @interface EnableRuleMigrationSupport {
159
}
160
```
161
162
### External Resource Support
163
164
Provides native support for subclasses of the ExternalResource rule from JUnit 4.
165
166
```java { .api }
167
/**
168
* Extension providing native support for subclasses of ExternalResource rule from JUnit 4.
169
* Supports both @Rule-annotated fields and methods.
170
*
171
* API Status: STABLE (since 5.7)
172
* Since: 5.0
173
*/
174
public class ExternalResourceSupport implements BeforeEachCallback, AfterEachCallback {
175
176
/**
177
* Creates a new ExternalResourceSupport instance.
178
*/
179
public ExternalResourceSupport();
180
181
/**
182
* Called before each test method execution to set up external resources.
183
* @param context the current extension context
184
* @throws Exception if resource setup fails
185
*/
186
@Override
187
public void beforeEach(ExtensionContext context) throws Exception;
188
189
/**
190
* Called after each test method execution to clean up external resources.
191
* @param context the current extension context
192
* @throws Exception if resource cleanup fails
193
*/
194
@Override
195
public void afterEach(ExtensionContext context) throws Exception;
196
}
197
```
198
199
### Verifier Support
200
201
Provides native support for subclasses of the Verifier rule from JUnit 4.
202
203
```java { .api }
204
/**
205
* Extension providing native support for subclasses of Verifier rule from JUnit 4.
206
* Supports both @Rule-annotated fields and methods.
207
*
208
* API Status: STABLE (since 5.7)
209
* Since: 5.0
210
*/
211
public class VerifierSupport implements AfterEachCallback {
212
213
/**
214
* Creates a new VerifierSupport instance.
215
*/
216
public VerifierSupport();
217
218
/**
219
* Called after each test method execution to perform verification.
220
* @param context the current extension context
221
* @throws Exception if verification fails
222
*/
223
@Override
224
public void afterEach(ExtensionContext context) throws Exception;
225
}
226
```
227
228
### Expected Exception Support
229
230
Provides native support for the ExpectedException rule from JUnit 4.
231
232
```java { .api }
233
/**
234
* Extension providing native support for the ExpectedException rule from JUnit 4.
235
* Handles test execution exceptions and validates expected exceptions.
236
*
237
* API Status: STABLE (since 5.7)
238
* Since: 5.0
239
*/
240
public class ExpectedExceptionSupport implements AfterEachCallback, TestExecutionExceptionHandler {
241
242
/**
243
* Creates a new ExpectedExceptionSupport instance.
244
*/
245
public ExpectedExceptionSupport();
246
247
/**
248
* Handles test execution exceptions, checking against expected exceptions.
249
* @param context the current extension context
250
* @param throwable the exception that occurred during test execution
251
* @throws Throwable if the exception should not be handled
252
*/
253
@Override
254
public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable;
255
256
/**
257
* Called after each test method execution to validate expected exceptions.
258
* @param context the current extension context
259
* @throws Exception if expected exception validation fails
260
*/
261
@Override
262
public void afterEach(ExtensionContext context) throws Exception;
263
}
264
```
265
266
### Ignore Condition Support
267
268
ExecutionCondition that supports JUnit 4's @Ignore annotation for disabling test classes and methods.
269
270
```java { .api }
271
/**
272
* ExecutionCondition that supports JUnit 4's @Ignore annotation.
273
* Containers/tests are disabled if @Ignore is present on the test class or method.
274
*
275
* API Status: STABLE (since 5.7)
276
* Since: 5.4
277
*/
278
public class IgnoreCondition implements ExecutionCondition {
279
280
/**
281
* Creates a new IgnoreCondition instance.
282
*/
283
public IgnoreCondition();
284
285
/**
286
* Evaluates the execution condition based on the presence of @Ignore annotation.
287
* @param context the current extension context
288
* @return ConditionEvaluationResult indicating whether execution should proceed
289
*/
290
@Override
291
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context);
292
}
293
```
294
295
### Advanced Adapter Support
296
297
**Note**: The following adapter classes are part of the INTERNAL API but are exported by the module for advanced usage scenarios.
298
299
#### Generic Before/After Advice Interface
300
301
Base interface for generic before/after advice used by rule adapters.
302
303
```java { .api }
304
/**
305
* Interface for generic before/after advice used by rule adapters.
306
*
307
* API Status: INTERNAL (since 5.0)
308
*/
309
public interface GenericBeforeAndAfterAdvice {
310
311
/**
312
* Called before test execution. Default implementation does nothing.
313
*/
314
default void before();
315
316
/**
317
* Handles test execution exceptions. Default implementation does nothing.
318
* @param cause the exception that occurred during test execution
319
* @throws Throwable if the exception should be rethrown
320
*/
321
default void handleTestExecutionException(Throwable cause) throws Throwable;
322
323
/**
324
* Called after test execution. Default implementation does nothing.
325
*/
326
default void after();
327
}
328
```
329
330
#### Abstract Test Rule Adapter
331
332
Base adapter class for converting JUnit 4 TestRule to JUnit Jupiter extensions.
333
334
```java { .api }
335
/**
336
* Base adapter class for converting JUnit 4 TestRule to JUnit Jupiter extensions.
337
*
338
* API Status: INTERNAL (since 5.0)
339
*/
340
public abstract class AbstractTestRuleAdapter implements GenericBeforeAndAfterAdvice {
341
342
/**
343
* Creates a new adapter for the specified rule-annotated member.
344
* @param annotatedMember the @Rule-annotated field or method
345
* @param adapteeClass the expected rule class type
346
*/
347
public AbstractTestRuleAdapter(TestRuleAnnotatedMember annotatedMember, Class<? extends TestRule> adapteeClass);
348
349
/**
350
* Executes a method on the target rule with no parameters.
351
* @param name the method name to execute
352
* @return the method result
353
*/
354
protected Object executeMethod(String name);
355
356
/**
357
* Executes a method on the target rule with specified parameters.
358
* @param methodName the method name to execute
359
* @param parameterTypes the parameter types
360
* @param arguments the method arguments
361
* @return the method result
362
*/
363
protected Object executeMethod(String methodName, Class<?>[] parameterTypes, Object... arguments);
364
}
365
```
366
367
#### External Resource Adapter
368
369
Adapter for ExternalResource rules.
370
371
```java { .api }
372
/**
373
* Adapter for ExternalResource rules.
374
*
375
* API Status: INTERNAL (since 5.0)
376
*/
377
public class ExternalResourceAdapter extends AbstractTestRuleAdapter {
378
379
/**
380
* Creates a new ExternalResourceAdapter for the specified annotated member.
381
* @param annotatedMember the @Rule-annotated field or method containing an ExternalResource
382
*/
383
public ExternalResourceAdapter(TestRuleAnnotatedMember annotatedMember);
384
385
/**
386
* Called before test execution to set up the external resource.
387
*/
388
@Override
389
public void before();
390
391
/**
392
* Called after test execution to clean up the external resource.
393
*/
394
@Override
395
public void after();
396
}
397
```
398
399
#### Verifier Adapter
400
401
Adapter for Verifier rules.
402
403
```java { .api }
404
/**
405
* Adapter for Verifier rules.
406
*
407
* API Status: INTERNAL (since 5.0)
408
*/
409
public class VerifierAdapter extends AbstractTestRuleAdapter {
410
411
/**
412
* Creates a new VerifierAdapter for the specified annotated member.
413
* @param annotatedMember the @Rule-annotated field or method containing a Verifier
414
*/
415
public VerifierAdapter(TestRuleAnnotatedMember annotatedMember);
416
417
/**
418
* Called after test execution to perform verification.
419
*/
420
@Override
421
public void after();
422
}
423
```
424
425
#### Expected Exception Adapter
426
427
Adapter for ExpectedException rules.
428
429
```java { .api }
430
/**
431
* Adapter for ExpectedException rules.
432
*
433
* API Status: INTERNAL (since 5.0)
434
*/
435
public class ExpectedExceptionAdapter extends AbstractTestRuleAdapter {
436
437
/**
438
* Creates a new ExpectedExceptionAdapter for the specified annotated member.
439
* @param annotatedMember the @Rule-annotated field or method containing an ExpectedException
440
*/
441
public ExpectedExceptionAdapter(TestRuleAnnotatedMember annotatedMember);
442
443
/**
444
* Handles test execution exceptions, checking against expected exceptions.
445
* @param cause the exception that occurred during test execution
446
* @throws Throwable if the exception should not be handled
447
*/
448
@Override
449
public void handleTestExecutionException(Throwable cause) throws Throwable;
450
451
/**
452
* Called after test execution to validate expected exceptions.
453
*/
454
@Override
455
public void after();
456
}
457
```
458
459
### Rule Member Support
460
461
**Note**: The following member classes are part of the INTERNAL API but are exported by the module for advanced usage scenarios.
462
463
#### Test Rule Annotated Member Interface
464
465
Interface representing a @Rule-annotated member (field or method).
466
467
```java { .api }
468
/**
469
* Interface representing a @Rule-annotated member (field or method).
470
* Used internally by the migration support system.
471
*
472
* API Status: INTERNAL (since 5.0)
473
*/
474
public interface TestRuleAnnotatedMember {
475
476
/**
477
* Returns the TestRule instance from this annotated member.
478
* @return the TestRule instance
479
*/
480
TestRule getTestRule();
481
}
482
```
483
484
#### Test Rule Annotated Field
485
486
Represents a @Rule-annotated field containing a TestRule instance.
487
488
```java { .api }
489
/**
490
* Represents a @Rule-annotated field containing a TestRule instance.
491
*
492
* API Status: INTERNAL (since 5.1)
493
*/
494
public class TestRuleAnnotatedField implements TestRuleAnnotatedMember {
495
496
/**
497
* Creates a new TestRuleAnnotatedField for the specified field.
498
* @param testInstance the test instance containing the field
499
* @param field the @Rule-annotated field
500
*/
501
public TestRuleAnnotatedField(Object testInstance, Field field);
502
}
503
```
504
505
#### Test Rule Annotated Method
506
507
Represents a @Rule-annotated method that returns a TestRule instance.
508
509
```java { .api }
510
/**
511
* Represents a @Rule-annotated method that returns a TestRule instance.
512
*
513
* API Status: INTERNAL (since 5.1)
514
*/
515
public class TestRuleAnnotatedMethod implements TestRuleAnnotatedMember {
516
517
/**
518
* Creates a new TestRuleAnnotatedMethod for the specified method.
519
* @param testInstance the test instance containing the method
520
* @param method the @Rule-annotated method
521
*/
522
public TestRuleAnnotatedMethod(Object testInstance, Method method);
523
}
524
```
525
526
## Types
527
528
### JUnit Jupiter Extension Types
529
530
```java { .api }
531
// Core JUnit Jupiter extension interfaces used by migration support
532
// From org.junit.jupiter.api.extension package
533
534
interface BeforeEachCallback extends Extension {
535
/**
536
* Callback that is invoked before each test is invoked.
537
* @param context the current extension context
538
* @throws Exception if callback execution fails
539
*/
540
void beforeEach(ExtensionContext context) throws Exception;
541
}
542
543
interface AfterEachCallback extends Extension {
544
/**
545
* Callback that is invoked after each test has been invoked.
546
* @param context the current extension context
547
* @throws Exception if callback execution fails
548
*/
549
void afterEach(ExtensionContext context) throws Exception;
550
}
551
552
interface TestExecutionExceptionHandler extends Extension {
553
/**
554
* Handle the supplied throwable.
555
* @param context the current extension context
556
* @param throwable the Throwable to handle
557
* @throws Throwable if handling fails or the exception should be rethrown
558
*/
559
void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable;
560
}
561
562
interface ExecutionCondition extends Extension {
563
/**
564
* Evaluate the execution condition for the supplied ExtensionContext.
565
* @param context the current extension context
566
* @return the result of evaluating the condition
567
*/
568
ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context);
569
}
570
571
interface ExtensionContext {
572
/**
573
* Get the AnnotatedElement corresponding to the current extension context.
574
*/
575
Optional<AnnotatedElement> getElement();
576
577
/**
578
* Get the test instance associated with the current test or container.
579
*/
580
Object getRequiredTestInstance();
581
582
/**
583
* Get the Class associated with the current test or container.
584
*/
585
Class<?> getRequiredTestClass();
586
587
/**
588
* Get the unique ID of the current test or container.
589
*/
590
String getUniqueId();
591
592
/**
593
* Get the Store for the supplied Namespace.
594
*/
595
Store getStore(Namespace namespace);
596
}
597
598
interface ConditionEvaluationResult {
599
/**
600
* Whether the container or test should be disabled.
601
*/
602
boolean isDisabled();
603
604
/**
605
* Get the reason why the container or test should be disabled or enabled.
606
*/
607
Optional<String> getReason();
608
609
/**
610
* Factory method for creating enabled results.
611
*/
612
static ConditionEvaluationResult enabled(String reason);
613
614
/**
615
* Factory method for creating disabled results.
616
*/
617
static ConditionEvaluationResult disabled(String reason);
618
}
619
```
620
621
### JUnit 4 Rule Types
622
623
```java { .api }
624
// JUnit 4 types referenced by migration support
625
// From org.junit.rules package
626
627
interface TestRule {
628
/**
629
* Modifies the method-running Statement to implement this test-running rule.
630
* @param base the Statement to be modified
631
* @param description a Description of the test implemented in base
632
* @return a new statement, which may be the same as base
633
*/
634
Statement apply(Statement base, Description description);
635
}
636
637
abstract class Verifier implements TestRule {
638
/**
639
* Override this to add verification logic.
640
* @throws Throwable if verification fails
641
*/
642
protected abstract void verify() throws Throwable;
643
}
644
645
abstract class ExternalResource implements TestRule {
646
/**
647
* Override to set up your specific external resource.
648
* @throws Throwable if setup fails
649
*/
650
protected void before() throws Throwable;
651
652
/**
653
* Override to tear down your specific external resource.
654
*/
655
protected void after();
656
}
657
658
class ExpectedException implements TestRule {
659
/**
660
* Returns a Rule that expects no exception to be thrown.
661
*/
662
public static ExpectedException none();
663
664
/**
665
* Specifies the failure message for tests that are expected to throw an exception but do not.
666
* @param message exception message
667
*/
668
public void reportMissingExceptionWithMessage(String message);
669
670
/**
671
* Specifies that the test is expected to throw an exact type of exception.
672
* @param type the exception type
673
*/
674
public void expect(Class<? extends Throwable> type);
675
676
/**
677
* Specifies that the test is expected to throw an exception with the given message.
678
* @param message the expected message
679
*/
680
public void expectMessage(String message);
681
}
682
```
683
684
### Java Reflection Types
685
686
```java { .api }
687
// Java reflection types used by migration support
688
// From java.lang.reflect package
689
690
class Field extends AccessibleObject implements Member {
691
// Standard Java reflection Field class
692
}
693
694
class Method extends Executable {
695
// Standard Java reflection Method class
696
}
697
698
interface AnnotatedElement {
699
// Standard Java reflection AnnotatedElement interface
700
}
701
```
702
703
## Error Handling
704
705
The migration support extensions handle various error scenarios:
706
707
- **Rule instantiation failures**: If @Rule-annotated methods fail to return valid TestRule instances
708
- **Test execution exceptions**: Properly routes exceptions through rule adapters for expected exception handling
709
- **Resource cleanup failures**: Ensures proper cleanup even when exceptions occur during test execution
710
- **Invalid rule types**: Only supports Verifier, ExternalResource, and ExpectedException rule types
711
712
## Limitations
713
714
- **Limited Rule Support**: Only supports subclasses of `org.junit.rules.Verifier`, `org.junit.rules.ExternalResource`, and `org.junit.rules.ExpectedException`
715
- **No Arbitrary TestRule Support**: General support for arbitrary `org.junit.rules.TestRule` implementations is not possible within the JUnit Jupiter extension model
716
- **Migration Purpose**: Primarily intended for migrating existing JUnit 4 codebases, not for new development
717
- **Import Statements**: Existing JUnit 4 rule import statements remain unchanged, including `org.junit.Rule` annotations
718
719
## Migration Guidelines
720
721
1. **Use for Legacy Code**: This module is designed for migrating existing JUnit 4 test suites with minimal changes
722
2. **Prefer Native Extensions**: For new development, use JUnit Jupiter's native extension model instead of JUnit 4 rules
723
3. **Gradual Migration**: Enable migration support to allow time for converting rules to native extensions
724
4. **Rule Compatibility**: Verify that your existing rules are subclasses of supported rule types
725
5. **Annotation Placement**: Apply migration annotations at the class level to enable rule support for the entire test class