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.0JUnit 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.
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.12.2</version>
<scope>test</scope>
</dependency>For Gradle:
testImplementation 'org.junit.vintage:junit-vintage-engine:5.12.2'import org.junit.vintage.engine.VintageTestEngine;
import org.junit.vintage.engine.Constants;
import org.apiguardian.api.API;The JUnit Vintage Engine is automatically discovered by the JUnit Platform when present on the classpath. No explicit configuration is required for basic usage.
// JUnit 4 test example - will be executed by Vintage Engine
import org.junit.Test;
import static org.junit.Assert.*;
public class LegacyJUnit4Test {
@Test
public void testSomething() {
assertEquals("Expected behavior", "actual", "expected");
}
}Configuration via system properties:
// Enable parallel execution
System.setProperty(Constants.PARALLEL_EXECUTION_ENABLED, "true");
System.setProperty(Constants.PARALLEL_CLASS_EXECUTION, "true");
System.setProperty(Constants.PARALLEL_POOL_SIZE, "4");The JUnit Vintage Engine operates as a bridge component within the JUnit Platform ecosystem:
TestEngine implementationCore TestEngine interface implementation that integrates with the JUnit Platform. This class is internal and automatically managed by the JUnit Platform via Service Loader discovery.
@API(status = INTERNAL, since = "4.12")
public final class VintageTestEngine implements TestEngine {
public String getId(); // Returns "junit-vintage"
public Optional<String> getGroupId(); // Returns "org.junit.vintage"
public Optional<String> getArtifactId(); // Returns "junit-vintage-engine"
public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId);
public void execute(ExecutionRequest request);
}Configuration properties for controlling engine behavior, particularly parallel execution.
@API(status = STABLE, since = "5.12")
public final class Constants {
// Parallel execution configuration (EXPERIMENTAL features)
@API(status = EXPERIMENTAL, since = "5.12")
public static final String PARALLEL_EXECUTION_ENABLED = "junit.vintage.execution.parallel.enabled";
@API(status = EXPERIMENTAL, since = "5.12")
public static final String PARALLEL_POOL_SIZE = "junit.vintage.execution.parallel.pool-size";
@API(status = EXPERIMENTAL, since = "5.12")
public static final String PARALLEL_CLASS_EXECUTION = "junit.vintage.execution.parallel.classes";
@API(status = EXPERIMENTAL, since = "5.12")
public static final String PARALLEL_METHOD_EXECUTION = "junit.vintage.execution.parallel.methods";
}The VintageTestEngine is automatically registered through the Java Service Loader mechanism:
Service Configuration: META-INF/services/org.junit.platform.engine.TestEngine
Implementation: org.junit.vintage.engine.VintageTestEngine
Enable parallel execution for improved performance:
// Set system properties programmatically
System.setProperty(Constants.PARALLEL_EXECUTION_ENABLED, "true");
System.setProperty(Constants.PARALLEL_CLASS_EXECUTION, "true");
System.setProperty(Constants.PARALLEL_METHOD_EXECUTION, "false");
System.setProperty(Constants.PARALLEL_POOL_SIZE, "8");Via JVM arguments:
-Djunit.vintage.execution.parallel.enabled=true
-Djunit.vintage.execution.parallel.classes=true
-Djunit.vintage.execution.parallel.pool-size=4The engine supports all standard JUnit 3 and 4 features:
// JUnit 3 style test
import junit.framework.TestCase;
public class LegacyJUnit3Test extends TestCase {
public void testOldStyle() {
assertEquals("JUnit 3 works", 2, 1 + 1);
}
}
// JUnit 4 with annotations and rules
import org.junit.Test;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
public class LegacyJUnit4Test {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testWithRule() {
thrown.expect(IllegalArgumentException.class);
throw new IllegalArgumentException("Expected");
}
}The engine provides identification information through the TestEngine interface (note: direct instantiation is not recommended as the engine is managed by the platform):
// Engine identification (accessible via TestEngine interface)
String engineId = "junit-vintage";
Optional<String> groupId = Optional.of("org.junit.vintage");
Optional<String> artifactId = Optional.of("junit-vintage-engine");
// Engine discovery and execution are automatically handled by JUnit Platform
// through Service Loader mechanism when vintage engine is on the classpathMinimum JUnit 4 Version: The Vintage Engine requires JUnit 4.12 or later. Version compatibility is automatically checked at runtime.
<!-- JUnit 4 for legacy test execution (minimum 4.12) -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<!-- JUnit Platform Engine for integration -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-engine</artifactId>
<version>1.12.2</version>
</dependency>For Java 9+ module system:
module my.test.module {
requires org.junit.vintage.engine;
requires junit; // JUnit 4
requires org.junit.platform.engine;
}The engine handles various error scenarios gracefully:
JUnitException with clear error message suggesting to remove vintage engine or add junit:junit dependencyJUnitException if JUnit version is below 4.12junit.runner.Version.id()The Vintage Engine facilitates gradual migration from JUnit 4 to JUnit 5:
This enables incremental adoption without requiring wholesale test rewrites.
// Core API status annotations (from org.apiguardian.api)
@interface API {
Status status() default Status.INTERNAL;
String since() default "";
enum Status {
INTERNAL, DEPRECATED, EXPERIMENTAL, MAINTAINED, STABLE
}
}
// Core JUnit Platform interfaces used by the engine
interface TestEngine {
String getId();
Optional<String> getGroupId();
Optional<String> getArtifactId();
TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId);
void execute(ExecutionRequest request);
}
interface EngineDiscoveryRequest {
// Discovery request configuration containing selectors and filters
}
interface ExecutionRequest {
TestDescriptor getRootTestDescriptor();
EngineExecutionListener getEngineExecutionListener();
}
interface TestDescriptor {
UniqueId getUniqueId();
String getDisplayName();
Set<TestTag> getTags();
Optional<TestSource> getSource();
// Methods for test hierarchy management
}
// Exception thrown for JUnit-related failures
class JUnitException extends RuntimeException {
public JUnitException(String message);
public JUnitException(String message, Throwable cause);
}