JUnit Platform Suite API provides annotations and configuration options for creating test suites with the JUnit Platform, including test selection, filtering, and configuration capabilities for organizing and executing collections of tests
—
Configuration parameter management with support for inline parameters, properties files, and inheritance control from parent discovery requests.
Specifies individual configuration key-value pairs to be added to the discovery request.
/**
* Specifies a configuration key and value pair to be added to the discovery request.
* Repeatable annotation for multiple configuration parameters.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@Documented
@API(status = STABLE, since = "1.10")
@Repeatable(ConfigurationParameters.class)
public @interface ConfigurationParameter {
/**
* The configuration parameter key; never null or blank.
* @return configuration parameter key
*/
String key();
/**
* The value to add to the discovery request for the specified key.
* @return configuration parameter value
*/
String value();
}
/**
* Container for multiple @ConfigurationParameter declarations.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@Documented
@API(status = STABLE, since = "1.10")
public @interface ConfigurationParameters {
/**
* Array of @ConfigurationParameter declarations.
* @return array of configuration parameters
*/
ConfigurationParameter[] value();
}Usage Examples:
// Single configuration parameter
@Suite
@SelectPackages("com.example")
@ConfigurationParameter(
key = "junit.jupiter.displayname.generator.default",
value = "org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores"
)
public class CustomDisplayNameTestSuite {
}
// Multiple configuration parameters
@Suite
@SelectPackages("com.example")
@ConfigurationParameter(key = "junit.jupiter.execution.parallel.enabled", value = "true")
@ConfigurationParameter(key = "junit.jupiter.execution.parallel.mode.default", value = "concurrent")
@ConfigurationParameter(key = "junit.jupiter.execution.parallel.config.strategy", value = "dynamic")
public class ParallelExecutionTestSuite {
}
// Database configuration
@Suite
@SelectTags("database")
@ConfigurationParameter(key = "database.url", value = "jdbc:h2:mem:testdb")
@ConfigurationParameter(key = "database.username", value = "sa")
@ConfigurationParameter(key = "database.password", value = "")
@ConfigurationParameter(key = "database.pool.size", value = "5")
public class DatabaseTestSuite {
}Specifies configuration files in Java properties format to be loaded from the classpath.
/**
* Specifies a configuration file in Java's properties format on the classpath
* to be added to the discovery request.
* Repeatable annotation for multiple properties files.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@Documented
@API(status = EXPERIMENTAL, since = "1.11")
@Repeatable(ConfigurationParametersResources.class)
public @interface ConfigurationParametersResource {
/**
* The classpath location for the desired properties file; never null or blank.
* @return classpath resource path
*/
String value();
}
/**
* Container for multiple @ConfigurationParametersResource declarations.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@Documented
@API(status = EXPERIMENTAL, since = "1.11")
public @interface ConfigurationParametersResources {
/**
* Array of @ConfigurationParametersResource declarations.
* @return array of configuration parameter resources
*/
ConfigurationParametersResource[] value();
}Usage Examples:
// Single properties file
@Suite
@SelectPackages("com.example.integration")
@ConfigurationParametersResource("/test-config/integration.properties")
public class IntegrationTestSuite {
}
// Multiple properties files
@Suite
@SelectPackages("com.example")
@ConfigurationParametersResource("/test-config/database.properties")
@ConfigurationParametersResource("/test-config/security.properties")
@ConfigurationParametersResource("/test-config/logging.properties")
public class MultiConfigTestSuite {
}
// Environment-specific configuration
@Suite
@SelectTags("performance")
@ConfigurationParametersResource("/test-config/performance-${test.env:local}.properties")
public class PerformanceTestSuite {
}Example properties file (/test-config/integration.properties):
# Database configuration
database.url=jdbc:h2:mem:integration_test
database.username=test_user
database.password=test_pass
# JUnit Jupiter configuration
junit.jupiter.execution.timeout.default=30s
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
# Custom application configuration
app.feature.flags.enabled=true
app.mock.external.services=true
app.log.level=DEBUGDisables inheritance of configuration parameters from parent discovery requests.
/**
* Disable parent configuration parameters.
*
* By default, a suite discovers tests using both explicit configuration parameters
* and configuration parameters from the discovery request that discovered the suite.
* This annotation disables the latter source so that only explicit configuration
* parameters are taken into account.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@Documented
@API(status = STABLE, since = "1.10")
public @interface DisableParentConfigurationParameters {
}Usage Examples:
// Isolated test suite with only explicit configuration
@Suite
@SelectPackages("com.example.isolated")
@DisableParentConfigurationParameters
@ConfigurationParameter(key = "junit.jupiter.execution.parallel.enabled", value = "false")
@ConfigurationParameter(key = "app.test.mode", value = "isolated")
public class IsolatedTestSuite {
}
// Suite that ignores global CI configuration
@Suite
@SelectTags("local-only")
@DisableParentConfigurationParameters
@ConfigurationParametersResource("/test-config/local-development.properties")
public class LocalDevelopmentTestSuite {
}Configuration parameters are applied in the following order (highest to lowest precedence):
@Suite
@SelectPackages("com.example")
// These have highest precedence
@ConfigurationParameter(key = "parallel.enabled", value = "true")
@ConfigurationParameter(key = "timeout.default", value = "60s")
// These have medium precedence
@ConfigurationParametersResource("/config/base.properties")
@ConfigurationParametersResource("/config/override.properties")
// Parent parameters have lowest precedence (unless disabled)
public class ConfigurationHierarchyTestSuite {
}Parallel execution configuration:
@Suite
@SelectPackages("com.example.unit")
@ConfigurationParameter(key = "junit.jupiter.execution.parallel.enabled", value = "true")
@ConfigurationParameter(key = "junit.jupiter.execution.parallel.mode.default", value = "concurrent")
@ConfigurationParameter(key = "junit.jupiter.execution.parallel.config.strategy", value = "dynamic")
@ConfigurationParameter(key = "junit.jupiter.execution.parallel.config.dynamic.factor", value = "0.8")
public class ParallelTestSuite {
}Timeout configuration:
@Suite
@SelectTags("integration")
@ConfigurationParameter(key = "junit.jupiter.execution.timeout.default", value = "5m")
@ConfigurationParameter(key = "junit.jupiter.execution.timeout.testable.method.default", value = "2m")
@ConfigurationParameter(key = "junit.jupiter.execution.timeout.testtemplate.method.default", value = "3m")
public class TimeoutConfiguredTestSuite {
}Display name configuration:
@Suite
@SelectPackages("com.example")
@ConfigurationParameter(
key = "junit.jupiter.displayname.generator.default",
value = "org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores"
)
public class ReadableDisplayNameTestSuite {
}Development environment:
@Suite
@SelectPackages("com.example")
@ConfigurationParametersResource("/config/development.properties")
@ConfigurationParameter(key = "app.debug.enabled", value = "true")
@ConfigurationParameter(key = "app.mock.external", value = "true")
public class DevelopmentTestSuite {
}CI/CD environment:
@Suite
@SelectPackages("com.example")
@DisableParentConfigurationParameters // Ignore local dev config
@ConfigurationParametersResource("/config/ci.properties")
@ConfigurationParameter(key = "junit.jupiter.execution.parallel.enabled", value = "true")
@ConfigurationParameter(key = "app.strict.validation", value = "true")
public class CiTestSuite {
}Production-like environment:
@Suite
@SelectTags("production-ready")
@ConfigurationParametersResource("/config/production-test.properties")
@ConfigurationParameter(key = "app.mock.external", value = "false")
@ConfigurationParameter(key = "app.security.strict", value = "true")
@ConfigurationParameter(key = "database.pool.size", value = "20")
public class ProductionTestSuite {
}Recommended file structure:
src/test/resources/
├── test-config/
│ ├── base.properties # Common configuration
│ ├── development.properties # Development overrides
│ ├── ci.properties # CI/CD specific
│ ├── integration.properties # Integration test config
│ ├── performance.properties # Performance test config
│ └── security.properties # Security test configBase configuration file (base.properties):
# Common JUnit configuration
junit.jupiter.execution.timeout.default=30s
junit.jupiter.displayname.generator.default=org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores
# Common application configuration
app.log.level=INFO
app.test.data.cleanup=trueIntegration configuration file (integration.properties):
# Include base configuration (manually or via tooling)
# Database configuration
database.url=jdbc:h2:mem:integration_test
database.username=integration_user
database.pool.size=10
# External services
app.mock.external.services=true
app.external.api.timeout=10s
# Parallel execution for integration tests
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=same_thread
junit.jupiter.execution.parallel.mode.classes.default=concurrentSystem property substitution:
@Suite
@SelectPackages("com.example")
@ConfigurationParameter(key = "database.url", value = "${test.db.url:jdbc:h2:mem:testdb}")
@ConfigurationParameter(key = "app.profile", value = "${test.profile:test}")
public class DynamicConfigTestSuite {
}Conditional configuration:
// Different suites for different environments
@Suite
@SelectPackages("com.example")
@ConfigurationParametersResource("/config/${test.env:local}.properties")
public class EnvironmentAwareTestSuite {
}Validating configuration in suite setup:
@Suite
@SelectPackages("com.example.database")
@ConfigurationParametersResource("/config/database.properties")
public class DatabaseTestSuite {
@BeforeSuite
static void validateConfiguration() {
String dbUrl = System.getProperty("database.url");
if (dbUrl == null || dbUrl.trim().isEmpty()) {
throw new IllegalStateException("Database URL must be configured");
}
String poolSize = System.getProperty("database.pool.size", "5");
try {
int size = Integer.parseInt(poolSize);
if (size < 1 || size > 50) {
throw new IllegalStateException("Database pool size must be between 1 and 50");
}
} catch (NumberFormatException e) {
throw new IllegalStateException("Invalid database pool size: " + poolSize);
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-junit-platform--junit-platform-suite-api