JUnit Jupiter aggregator module providing a unified API for JUnit 5 testing framework with core API, parameterized tests, and test engine.
—
Configuration for parallel test execution, resource locking, and temporary file management. JUnit Jupiter provides fine-grained control over test concurrency and resource access.
import org.junit.jupiter.api.parallel.*;
import org.junit.jupiter.api.io.TempDir;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.*;Control concurrent execution of tests and test classes.
/**
* Configure parallel execution mode for tests
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Execution {
/**
* Execution mode for this test or test class
*/
ExecutionMode value();
}
/**
* Execution mode enumeration
*/
enum ExecutionMode {
/**
* Execute in same thread as parent
*/
SAME_THREAD,
/**
* Execute concurrently with other tests (if parallel execution enabled)
*/
CONCURRENT
}Usage Examples:
// Enable concurrent execution for entire test class
@Execution(ExecutionMode.CONCURRENT)
class ParallelTest {
@Test
void test1() {
// Runs concurrently with other tests
performIndependentOperation();
}
@Test
void test2() {
// Runs concurrently with other tests
performAnotherIndependentOperation();
}
@Test
@Execution(ExecutionMode.SAME_THREAD)
void sequentialTest() {
// Runs sequentially despite class-level concurrent setting
performSequentialOperation();
}
}
// Mixed execution modes
class MixedExecutionTest {
@Test
@Execution(ExecutionMode.CONCURRENT)
void concurrentTest1() {
// Runs concurrently
}
@Test
@Execution(ExecutionMode.CONCURRENT)
void concurrentTest2() {
// Runs concurrently
}
@Test
void defaultTest() {
// Uses default execution mode
}
}Force sequential execution for tests that require isolation.
/**
* Force sequential execution in separate classloader
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Isolated {
}Usage Example:
@Isolated
class IsolatedTest {
@Test
void testThatModifiesGlobalState() {
System.setProperty("test.mode", "isolated");
// Test runs in isolation
}
@Test
void anotherIsolatedTest() {
// Also runs in isolation
}
}
class RegularTest {
@Test
@Isolated
void isolatedMethod() {
// Only this method runs in isolation
}
@Test
void regularMethod() {
// Regular execution
}
}Coordinate access to shared resources across concurrent tests.
/**
* Lock access to a shared resource
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(ResourceLocks.class)
@interface ResourceLock {
/**
* Resource identifier
*/
String value();
/**
* Access mode for the resource
*/
ResourceAccessMode mode() default ResourceAccessMode.READ_WRITE;
/**
* Target level for the lock
*/
ResourceLockTarget target() default ResourceLockTarget.METHOD;
}
/**
* Container for multiple resource locks
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface ResourceLocks {
ResourceLock[] value();
}
/**
* Resource access mode
*/
enum ResourceAccessMode {
/**
* Exclusive read-write access
*/
READ_WRITE,
/**
* Shared read-only access
*/
READ
}
/**
* Resource lock target level
*/
enum ResourceLockTarget {
/**
* Lock applies to individual method
*/
METHOD,
/**
* Lock applies to entire class
*/
CLASS
}Usage Examples:
class ResourceLockTest {
@Test
@ResourceLock("database")
void testDatabaseWrite() {
// Exclusive access to database resource
database.insert("test data");
}
@Test
@ResourceLock(value = "database", mode = ResourceAccessMode.READ)
void testDatabaseRead1() {
// Shared read access - can run concurrently with other read tests
String data = database.select("test data");
assertNotNull(data);
}
@Test
@ResourceLock(value = "database", mode = ResourceAccessMode.READ)
void testDatabaseRead2() {
// Shared read access - can run concurrently with testDatabaseRead1
int count = database.count();
assertTrue(count >= 0);
}
@Test
@ResourceLocks({
@ResourceLock("database"),
@ResourceLock("filesystem")
})
void testMultipleResources() {
// Requires exclusive access to both database and filesystem
database.backup("/tmp/backup");
}
}
@ResourceLock(value = "system-properties", target = ResourceLockTarget.CLASS)
class SystemPropertiesTest {
@Test
void testSystemProperty1() {
System.setProperty("test.prop", "value1");
// Entire class has exclusive access to system properties
}
@Test
void testSystemProperty2() {
System.setProperty("test.prop", "value2");
// Sequential execution guaranteed
}
}Pre-defined resource identifiers for common shared resources.
/**
* Standard resource constants
*/
class Resources {
/**
* Global resource lock
*/
public static final String GLOBAL = "GLOBAL";
/**
* Java system properties
*/
public static final String SYSTEM_PROPERTIES = "SYSTEM_PROPERTIES";
/**
* Java system environment
*/
public static final String SYSTEM_ENVIRONMENT = "SYSTEM_ENVIRONMENT";
/**
* Standard input/output streams
*/
public static final String SYSTEM_OUT = "SYSTEM_OUT";
public static final String SYSTEM_ERR = "SYSTEM_ERR";
public static final String SYSTEM_IN = "SYSTEM_IN";
/**
* Java locale settings
*/
public static final String LOCALE = "LOCALE";
/**
* Java time zone settings
*/
public static final String TIME_ZONE = "TIME_ZONE";
}Usage Examples:
class StandardResourcesTest {
@Test
@ResourceLock(Resources.SYSTEM_PROPERTIES)
void testWithSystemProperties() {
String original = System.getProperty("user.dir");
System.setProperty("user.dir", "/tmp");
// Test with modified system property
assertEquals("/tmp", System.getProperty("user.dir"));
// Restore
System.setProperty("user.dir", original);
}
@Test
@ResourceLock(Resources.SYSTEM_OUT)
void testWithSystemOut() {
PrintStream originalOut = System.out;
ByteArrayOutputStream capturedOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(capturedOut));
System.out.println("Test output");
assertEquals("Test output\n", capturedOut.toString());
System.setOut(originalOut);
}
@Test
@ResourceLock(Resources.LOCALE)
void testWithLocale() {
Locale original = Locale.getDefault();
Locale.setDefault(Locale.FRENCH);
// Test with French locale
assertEquals(Locale.FRENCH, Locale.getDefault());
Locale.setDefault(original);
}
}Programmatically provide resource locks based on test context.
/**
* Provides resource locks programmatically
*/
interface ResourceLocksProvider {
/**
* Provide resource locks for the given extension context
*/
Set<Lock> provideForClass(ExtensionContext context);
Set<Lock> provideForNestedClass(ExtensionContext context);
Set<Lock> provideForMethod(ExtensionContext context);
/**
* Resource lock representation
*/
interface Lock {
String getKey();
ResourceAccessMode getAccessMode();
}
}Automatic temporary directory creation and cleanup for tests.
/**
* Inject temporary directory into test method or field
*/
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@interface TempDir {
/**
* Cleanup mode for temporary directory
*/
CleanupMode cleanup() default CleanupMode.DEFAULT;
/**
* Factory for creating temporary directories
*/
Class<? extends TempDirFactory> factory() default TempDirFactory.Standard.class;
}
/**
* Cleanup mode for temporary directories
*/
enum CleanupMode {
/**
* Use default cleanup behavior
*/
DEFAULT,
/**
* Never clean up temporary directories
*/
NEVER,
/**
* Always clean up temporary directories
*/
ALWAYS,
/**
* Clean up on success, keep on failure
*/
ON_SUCCESS
}
/**
* Factory for creating temporary directories
*/
interface TempDirFactory {
/**
* Create temporary directory
*/
Path createTempDirectory(AnnotatedElement annotatedElement, ExtensionContext extensionContext) throws IOException;
/**
* Standard temporary directory factory
*/
class Standard implements TempDirFactory {
@Override
public Path createTempDirectory(AnnotatedElement annotatedElement, ExtensionContext extensionContext) throws IOException {
return Files.createTempDirectory("junit");
}
}
}Usage Examples:
class TempDirTest {
@TempDir
Path sharedTempDir;
@Test
void testWithSharedTempDir() throws IOException {
Path file = sharedTempDir.resolve("test.txt");
Files.write(file, "test content".getBytes());
assertTrue(Files.exists(file));
assertEquals("test content", Files.readString(file));
}
@Test
void testWithMethodTempDir(@TempDir Path tempDir) throws IOException {
// Each test method gets its own temp directory
assertNotEquals(sharedTempDir, tempDir);
Path file = tempDir.resolve("method-test.txt");
Files.createFile(file);
assertTrue(Files.exists(file));
}
@Test
void testWithCustomCleanup(@TempDir(cleanup = CleanupMode.NEVER) Path persistentDir) throws IOException {
// This directory won't be cleaned up automatically
Path file = persistentDir.resolve("persistent.txt");
Files.write(file, "This file will persist".getBytes());
System.out.println("Persistent dir: " + persistentDir);
}
@Test
void testWithCustomFactory(@TempDir(factory = CustomTempDirFactory.class) Path customDir) {
// Directory created by custom factory
assertTrue(customDir.toString().contains("custom"));
}
}
class CustomTempDirFactory implements TempDirFactory {
@Override
public Path createTempDirectory(AnnotatedElement annotatedElement, ExtensionContext extensionContext) throws IOException {
return Files.createTempDirectory("custom-junit-" + extensionContext.getDisplayName());
}
}Configure parallel execution behavior through system properties or configuration files.
Key Configuration Properties:
# Enable parallel execution
junit.jupiter.execution.parallel.enabled=true
# Default execution mode
junit.jupiter.execution.parallel.mode.default=concurrent
# Class-level execution mode
junit.jupiter.execution.parallel.mode.classes.default=concurrent
# Parallelism strategy
junit.jupiter.execution.parallel.config.strategy=dynamic
# or fixed with custom thread count
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.config.fixed.parallelism=4
# Dynamic parallelism factor
junit.jupiter.execution.parallel.config.dynamic.factor=2.0Usage in junit-platform.properties:
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.mode.classes.default=same_thread
junit.jupiter.execution.parallel.config.strategy=dynamic
junit.jupiter.execution.parallel.config.dynamic.factor=1.5Install with Tessl CLI
npx tessl i tessl/maven-org-junit-jupiter--junit-jupiter