LauncherConfig does not effectively use system properties due to LauncherConfig.DEFAULT and unpopulated ConfigurationParameters context
Issue Description:
In JUnit Platform LauncherFactory , the no-argument LauncherFactory.create() method directly uses LauncherConfig.DEFAULT. This LauncherConfig.DEFAULT instance has its auto-registration booleans (e.g., testExecutionListenerAutoRegistrationEnabled) hardcoded to true within LauncherConfig.Builder and is not initialized based on values from an externally populated ConfigurationParameters instance.
This means directly invoking LauncherFactory.openSession() or LauncherFactory.create()(I tried both IDEA and gradle, they all use the LauncherFactory.openSession() and cannot modify) cannot effectively use system properties to control these common listener configuration aspects, as the necessary LauncherConfig booleans are predetermined and the ConfigurationParameters context used for deactivation isn't populated from external sources by LauncherFactory itself.
a simple code discribe:
public class LauncherFactory {
// IDEA or Gradle etc., start LauncherSession use this method
public static LauncherSession openSession() throws PreconditionViolationException {
return openSession(LauncherConfig.DEFAULT);
}
@API(status = STABLE, since = "1.10")
public static LauncherSession openSession(LauncherConfig config) throws PreconditionViolationException {
// here can we set system property to affect `testExecutionListenerAutoRegistrationEnabled`
LauncherConfigurationParameters configurationParameters = LauncherConfigurationParameters.builder().build();
return new DefaultLauncherSession(collectLauncherInterceptors(configurationParameters),
() -> createLauncherSessionListener(config), () -> createDefaultLauncher(config, configurationParameters));
}
private static DefaultLauncher createDefaultLauncher(LauncherConfig config,
LauncherConfigurationParameters configurationParameters) {
// ...
registerTestExecutionListeners(config, launcher, configurationParameters);
return launcher;
}
private static void registerTestExecutionListeners(LauncherConfig config, Launcher launcher,
LauncherConfigurationParameters configurationParameters) {
// this always return true:
if (config.isTestExecutionListenerAutoRegistrationEnabled()) {
loadAndFilterTestExecutionListeners(configurationParameters).forEach(
launcher::registerTestExecutionListeners);
}
config.getAdditionalTestExecutionListeners().forEach(launcher::registerTestExecutionListeners);
}
private static Stream<TestExecutionListener> loadAndFilterTestExecutionListeners(
ConfigurationParameters configurationParameters) {
// this `DEACTIVATE_LISTENERS_PATTERN_PROPERTY_NAME` can be read from system properties
String deactivatedListenersPattern = configurationParameters.get(
DEACTIVATE_LISTENERS_PATTERN_PROPERTY_NAME).orElse(null);
// ...
}
}
Suggested Solution:
1.Enhance LauncherFactory.create() (no-arg version): Instead of directly using LauncherConfig.DEFAULT, this method could internally:
- Create a
ConfigurationParametersinstance that is populated from standard sources (e.g., system properties, junit-platform.properties via a mechanism similar to LauncherConfigurationParametersAdapter). - Use this populated
ConfigurationParametersinstance to build aLauncherConfig(e.g., by passing relevant string values from it to LauncherConfig.builder().enableTestExecutionListenerAutoRegistration(converter.toBoolean(params.get(...))), etc.). - This newly built LauncherConfig would then be passed to create(LauncherConfig config).
- The populated ConfigurationParameters instance (or one derived from it) should also be the one used by loadAndFilterTestExecutionListeners.
2.Modify
LauncherConfig.DEFAULT's initialization:LauncherConfig.DEFAULTcould be initialized (lazily or at static init time) with aLauncherConfiginstance that is built by consulting a globally accessible, pre-populatedConfigurationParametersinstance (which itself loads from system properties, etc.). This would makeLauncherConfig.DEFAULTinherently reflect external configuration. This might be a more breaking change.
this can helps people who use the IDEA or gradle integrated test runner to control behavior in LauncherConfig
Thanks for raising this issue! If I understand correctly, you're asking for a way to control the boolean flags in LauncherConfig via system properties or configuration parameters. Could you please share your concrete use case? Is there a TestEngine/LauncherSessionListener/LauncherDiscoveryListener/TestExecutionListener/PostDiscoveryFilter that you wish to deactivate?
I'm not sure what you mean by "unpopulated ConfigurationParameters context" as they are currently not read from configuration parameters. Could you please elaborate?
Related existing configuration parameters:
junit.platform.execution.listeners.deactivatewhich allows deactivatingServiceLoader-registeredTestExecutionListenersjunit.jupiter.extensions.autodetection.include/excludewhich allows filtering which JupiterExtensionsget auto-registered (if auto-registration is enabled viajunit.jupiter.extensions.autodetection.enabledconfiguration parameter
thank you for reply! this is my use case: my project dependency including a jar which could not be modified, and the jar provided a spi service for TestExecutionListener,the listener import some class which cannot import to project dependency because of conflict (logback and log4j) so when a test run, the listener throws ClassNotFoundException during init
i tried use junit.platform.execution.listeners.deactivate to disable this listener, but i find it is call listener.getClass().getName() to filter,exception happened drying getClass.
i tried use testExecutionListenerAutoRegistrationEnabled to disable all listener, but idea/gradle both use the LauncherFactory.openSession() without argument, so there is no way to set it to false.
so , as a normal developer, we have no idea to prevent listener's exception during class init. a temporary way is overwrite it in project file, and load preferentially in /classes path
Thanks for providing more context! I think being able to disable these via configuration parameters makes sense. I'll discuss with the team and will get back to you.