JUnit Vintage Engine provides a TestEngine for running JUnit 3 and 4 based tests on the JUnit Platform.
npx @tessl/cli install tessl/maven-org-junit-vintage--junit-vintage-engine@5.12.00
# JUnit Vintage Engine
1
2
JUnit Vintage Engine provides a TestEngine for running JUnit 3 and 4 based tests on the JUnit Platform. This engine allows existing JUnit 3 and 4 tests to be executed in the modern JUnit 5 ecosystem without modification, providing backward compatibility and migration support for legacy test suites.
3
4
## Package Information
5
6
- **Package Name**: junit-vintage-engine
7
- **Package Type**: Maven
8
- **Group ID**: org.junit.vintage
9
- **Artifact ID**: junit-vintage-engine
10
- **Language**: Java
11
- **Installation**: Add to Maven dependencies:
12
13
```xml
14
<dependency>
15
<groupId>org.junit.vintage</groupId>
16
<artifactId>junit-vintage-engine</artifactId>
17
<version>5.12.2</version>
18
<scope>test</scope>
19
</dependency>
20
```
21
22
For Gradle:
23
24
```groovy
25
testImplementation 'org.junit.vintage:junit-vintage-engine:5.12.2'
26
```
27
28
## Core Imports
29
30
```java
31
import org.junit.vintage.engine.VintageTestEngine;
32
import org.junit.vintage.engine.Constants;
33
import org.apiguardian.api.API;
34
```
35
36
## Basic Usage
37
38
The JUnit Vintage Engine is automatically discovered by the JUnit Platform when present on the classpath. No explicit configuration is required for basic usage.
39
40
```java
41
// JUnit 4 test example - will be executed by Vintage Engine
42
import org.junit.Test;
43
import static org.junit.Assert.*;
44
45
public class LegacyJUnit4Test {
46
@Test
47
public void testSomething() {
48
assertEquals("Expected behavior", "actual", "expected");
49
}
50
}
51
```
52
53
Configuration via system properties:
54
55
```java
56
// Enable parallel execution
57
System.setProperty(Constants.PARALLEL_EXECUTION_ENABLED, "true");
58
System.setProperty(Constants.PARALLEL_CLASS_EXECUTION, "true");
59
System.setProperty(Constants.PARALLEL_POOL_SIZE, "4");
60
```
61
62
## Architecture
63
64
The JUnit Vintage Engine operates as a bridge component within the JUnit Platform ecosystem:
65
66
- **Service Discovery**: Registered via Java Service Loader as a `TestEngine` implementation
67
- **Test Discovery**: Discovers JUnit 3 and 4 tests using legacy discovery mechanisms
68
- **Test Execution**: Executes legacy tests through JUnit 4's Runner API
69
- **Platform Integration**: Translates JUnit 3/4 execution events to JUnit Platform events
70
- **Parallel Execution**: Optional parallel execution capabilities for improved performance
71
72
## Capabilities
73
74
### TestEngine Implementation
75
76
Core TestEngine interface implementation that integrates with the JUnit Platform. This class is internal and automatically managed by the JUnit Platform via Service Loader discovery.
77
78
```java { .api }
79
@API(status = INTERNAL, since = "4.12")
80
public final class VintageTestEngine implements TestEngine {
81
public String getId(); // Returns "junit-vintage"
82
public Optional<String> getGroupId(); // Returns "org.junit.vintage"
83
public Optional<String> getArtifactId(); // Returns "junit-vintage-engine"
84
public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId);
85
public void execute(ExecutionRequest request);
86
}
87
```
88
89
### Configuration Constants
90
91
Configuration properties for controlling engine behavior, particularly parallel execution.
92
93
```java { .api }
94
@API(status = STABLE, since = "5.12")
95
public final class Constants {
96
// Parallel execution configuration (EXPERIMENTAL features)
97
@API(status = EXPERIMENTAL, since = "5.12")
98
public static final String PARALLEL_EXECUTION_ENABLED = "junit.vintage.execution.parallel.enabled";
99
100
@API(status = EXPERIMENTAL, since = "5.12")
101
public static final String PARALLEL_POOL_SIZE = "junit.vintage.execution.parallel.pool-size";
102
103
@API(status = EXPERIMENTAL, since = "5.12")
104
public static final String PARALLEL_CLASS_EXECUTION = "junit.vintage.execution.parallel.classes";
105
106
@API(status = EXPERIMENTAL, since = "5.12")
107
public static final String PARALLEL_METHOD_EXECUTION = "junit.vintage.execution.parallel.methods";
108
}
109
```
110
111
## Engine Registration
112
113
The VintageTestEngine is automatically registered through the Java Service Loader mechanism:
114
115
**Service Configuration**: `META-INF/services/org.junit.platform.engine.TestEngine`
116
**Implementation**: `org.junit.vintage.engine.VintageTestEngine`
117
118
## Usage Examples
119
120
### Configuration Examples
121
122
Enable parallel execution for improved performance:
123
124
```java
125
// Set system properties programmatically
126
System.setProperty(Constants.PARALLEL_EXECUTION_ENABLED, "true");
127
System.setProperty(Constants.PARALLEL_CLASS_EXECUTION, "true");
128
System.setProperty(Constants.PARALLEL_METHOD_EXECUTION, "false");
129
System.setProperty(Constants.PARALLEL_POOL_SIZE, "8");
130
```
131
132
Via JVM arguments:
133
134
```bash
135
-Djunit.vintage.execution.parallel.enabled=true
136
-Djunit.vintage.execution.parallel.classes=true
137
-Djunit.vintage.execution.parallel.pool-size=4
138
```
139
140
### Legacy Test Compatibility
141
142
The engine supports all standard JUnit 3 and 4 features:
143
144
```java
145
// JUnit 3 style test
146
import junit.framework.TestCase;
147
148
public class LegacyJUnit3Test extends TestCase {
149
public void testOldStyle() {
150
assertEquals("JUnit 3 works", 2, 1 + 1);
151
}
152
}
153
154
// JUnit 4 with annotations and rules
155
import org.junit.Test;
156
import org.junit.Rule;
157
import org.junit.rules.ExpectedException;
158
159
public class LegacyJUnit4Test {
160
@Rule
161
public ExpectedException thrown = ExpectedException.none();
162
163
@Test
164
public void testWithRule() {
165
thrown.expect(IllegalArgumentException.class);
166
throw new IllegalArgumentException("Expected");
167
}
168
}
169
```
170
171
### Engine Information Access
172
173
The engine provides identification information through the TestEngine interface (note: direct instantiation is not recommended as the engine is managed by the platform):
174
175
```java
176
// Engine identification (accessible via TestEngine interface)
177
String engineId = "junit-vintage";
178
Optional<String> groupId = Optional.of("org.junit.vintage");
179
Optional<String> artifactId = Optional.of("junit-vintage-engine");
180
181
// Engine discovery and execution are automatically handled by JUnit Platform
182
// through Service Loader mechanism when vintage engine is on the classpath
183
```
184
185
## Integration Requirements
186
187
### Required Dependencies
188
189
**Minimum JUnit 4 Version**: The Vintage Engine requires JUnit 4.12 or later. Version compatibility is automatically checked at runtime.
190
191
```xml
192
<!-- JUnit 4 for legacy test execution (minimum 4.12) -->
193
<dependency>
194
<groupId>junit</groupId>
195
<artifactId>junit</artifactId>
196
<version>4.13.2</version>
197
</dependency>
198
199
<!-- JUnit Platform Engine for integration -->
200
<dependency>
201
<groupId>org.junit.platform</groupId>
202
<artifactId>junit-platform-engine</artifactId>
203
<version>1.12.2</version>
204
</dependency>
205
```
206
207
### Module System Support
208
209
For Java 9+ module system:
210
211
```java
212
module my.test.module {
213
requires org.junit.vintage.engine;
214
requires junit; // JUnit 4
215
requires org.junit.platform.engine;
216
}
217
```
218
219
## Error Handling
220
221
The engine handles various error scenarios gracefully:
222
223
- **Missing JUnit 4**: Throws `JUnitException` with clear error message suggesting to remove vintage engine or add junit:junit dependency
224
- **Incompatible JUnit 4 Version**: Throws `JUnitException` if JUnit version is below 4.12
225
- **Invalid Tests**: Properly reports discovery and execution failures through platform events
226
- **Platform Integration**: Translates legacy JUnit 3/4 exceptions to JUnit Platform events
227
- **Version Compatibility**: Automatic runtime validation using `junit.runner.Version.id()`
228
229
## Migration Support
230
231
The Vintage Engine facilitates gradual migration from JUnit 4 to JUnit 5:
232
233
1. **Phase 1**: Add JUnit Platform + Vintage Engine, run existing JUnit 4 tests
234
2. **Phase 2**: Gradually migrate tests to JUnit 5 (Jupiter) annotations
235
3. **Phase 3**: Remove Vintage Engine dependency when migration complete
236
237
This enables incremental adoption without requiring wholesale test rewrites.
238
239
## Types
240
241
```java { .api }
242
// Core API status annotations (from org.apiguardian.api)
243
@interface API {
244
Status status() default Status.INTERNAL;
245
String since() default "";
246
247
enum Status {
248
INTERNAL, DEPRECATED, EXPERIMENTAL, MAINTAINED, STABLE
249
}
250
}
251
252
// Core JUnit Platform interfaces used by the engine
253
interface TestEngine {
254
String getId();
255
Optional<String> getGroupId();
256
Optional<String> getArtifactId();
257
TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId);
258
void execute(ExecutionRequest request);
259
}
260
261
interface EngineDiscoveryRequest {
262
// Discovery request configuration containing selectors and filters
263
}
264
265
interface ExecutionRequest {
266
TestDescriptor getRootTestDescriptor();
267
EngineExecutionListener getEngineExecutionListener();
268
}
269
270
interface TestDescriptor {
271
UniqueId getUniqueId();
272
String getDisplayName();
273
Set<TestTag> getTags();
274
Optional<TestSource> getSource();
275
// Methods for test hierarchy management
276
}
277
278
// Exception thrown for JUnit-related failures
279
class JUnitException extends RuntimeException {
280
public JUnitException(String message);
281
public JUnitException(String message, Throwable cause);
282
}
283
```