As discussed in https://github.com/junit-team/junit5/issues/905#issuecomment-322001390, there is currently no native support for setting a _configuration parameter_ via the console launcher, Maven Surefire plugin, or Gradle plugin.
Thus, the only option from the build perspective is to set a system property or rely on the presence of a JUnit Platform _configuration file_ (see #1003).
For the JUnit Platform Gradle Plugin, you can set such a system property via a work-around that is discussed in https://github.com/junit-team/junit5/issues/475#issuecomment-242038043.
Introduce a --config command line option that expects a key=value pair.
java -jar junit-platform-console-standalone-*.jar \
--config junit.jupiter.extensions.autodetection.enabled=true \
--config junit.jupiter.testinstance.lifecycle.default=per_class
Align with the syntax supported for JVM system properties by Gradle tasks:
systemProperty('java.util.logging.manager', 'org.apache.logging.log4j.jul.LogManager')
This gives us:
junitPlatform {
// ...
configurationParameter('junit.jupiter.extensions.autodetection.enabled', 'true')
configurationParameter('junit.jupiter.testinstance.lifecycle.default', 'per_class')
// ...
}
Note, however, that the parentheses are optional in Groovy resulting in the following alternative syntax being supported out of the box.
junitPlatform {
// ...
configurationParameter 'junit.jupiter.extensions.autodetection.enabled', 'true'
configurationParameter 'junit.jupiter.testinstance.lifecycle.default', 'per_class'
// ...
}
Surefire does not support nested structures within properties, but that's not an issue if we take inspiration from Spring's support for inlined Properties in XML configuration, resulting in the following.
// ...
<build>
<plugins>
// ...
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<properties>
<excludeTags>integration, regression</excludeTags>
<configurationParameters>
junit.jupiter.extensions.autodetection.enabled = true
junit.jupiter.testinstance.lifecycle.default = per_class
</configurationParameters>
</properties>
</configuration>
<dependencies>
// ...
</dependencies>
</plugin>
</plugins>
</build>
// ...
For an example of how the configurationParameters can be converted to a Map<String, String> with full support for the java.util.Properties syntax, see https://github.com/junit-team/junit5/issues/1015#issuecomment-323584880.
I've updated the issue description with proposals for Console Launcher, Gradle, and Maven.
java -jar junit-platform-console-standalone-*.jar \
--config junit.jupiter.extensions.autodetection.enabled=true \
--config junit.jupiter.testinstance.lifecycle.default=PER_CLASS
junitPlatform {
// ...
configurationParameters = [
'junit.jupiter.extensions.autodetection.enabled': 'true',
'junit.jupiter.testinstance.lifecycle.default': 'PER_CLASS'
]
// ...
}
OR
junitPlatform {
// ...
configurationParameters['junit.jupiter.extensions.autodetection.enabled'] = 'true'
configurationParameters['junit.jupiter.testinstance.lifecycle.default'] = 'PER_CLASS'
// ...
}
Since Surefire does not support nested structures within properties our best option seems to be to do nothing and rely on the existing support for system properties.
...
<build>
<plugins>
...
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<systemPropertyVariables>
<junit.jupiter.extensions.autodetection.enabled>true</junit.jupiter.extensions.autodetection.enabled>
<junit.jupiter.testinstance.lifecycle.default>PER_CLASS</junit.jupiter.testinstance.lifecycle.default>
</systemPropertyVariables>
<properties>
<excludeTags>integration, regression</excludeTags>
</properties>
</configuration>
<dependencies>
...
</dependencies>
</plugin>
</plugins>
</build>
...
I think --config is perfect.
I think we should follow the same syntax supported for JVM system properties by Gradle tasks:
systemProperty('java.util.logging.manager', 'org.apache.logging.log4j.jul.LogManager')
This would give us:
junitPlatform {
// ...
configurationParameter('junit.jupiter.extensions.autodetection.enabled', 'true')
configurationParameter('junit.jupiter.testinstance.lifecycle.default', 'per_class')
// ...
}
I'm not a Surefire expert, but I honestly do not like relying on JVM system properties for this (unless there is literally no alternative). Rationale: system properties are technically not a first-class citizen in ConfigurationParameters and would never show up in invocations of toString() (e.g., while debugging or if we later decide to log the _contents_ of ConfigurationParameters at start-up (which I think is actually a good idea)).
I've updated the issue description with proposals for Console Launcher, Gradle, and Maven.
Thanks, @marcphilipp! 馃憤
Note that the parentheses are optional in my proposal for Gradle:
// configurationParameter('junit.jupiter.extensions.autodetection.enabled', 'true')
configurationParameter 'junit.jupiter.extensions.autodetection.enabled', 'true'
Since Surefire does not support nested structures within
propertiesour best option seems to be to do nothing and rely on the existing support for system properties.
We don't actually need a nested structure for this use case.
Rather, we can take inspiration from Spring's support for inlined Properties in XML configuration, resulting in the following.
...
<build>
<plugins>
...
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<properties>
<excludeTags>integration, regression</excludeTags>
<configurationParameters>
junit.jupiter.extensions.autodetection.enabled = true
junit.jupiter.testinstance.lifecycle.default = per_class
</configurationParameters>
</properties>
</configuration>
<dependencies>
...
</dependencies>
</plugin>
</plugins>
</build>
...
It's then straightforward to read in the String content of the configurationParameters key in the map returned by org.apache.maven.surefire.providerapi.ProviderParameters.getProviderProperties() and load a Properties object by treating the entire content as an in-memory file. The contents of the Properties object can then be converted into a Map<String,String> which is then passed to the Launcher API. That could look something like the following (authored in the web browser and therefore not compiled or tested).
Map<String, String> configParams = new HashMap<>();
String content = this.parameters.getProviderProperties().get("configurationParameters");
try (StringReader reader = new StringReader(content)) {
Properties props = new Properties();
props.load(reader);
props.forEach((key, value) -> configParams.put(String.valueOf(key), String.valueOf(value)));
}
catch (IOException ex) {
// TODO Log warning.
}
// pass configParams to LauncherDiscoveryRequestBuilder.configurationParameters()
I'm in favor of both the alternative proposals for Gradle and Maven.
Thanks, @sbrannen! 馃憤
Update: replaced original proposals in this issue's description with my alternative proposals.
_in progress_
@marcphilipp,
Just out of curiosity... what do you plan to do regarding the new "Prepare sample projects" deliverable?
I thought it might be a good idea to update the Maven and Gradle consumer projects to use the new properties. Do you think that's not necessary?
I thought it might be a good idea to update the Maven and Gradle consumer projects to use the new properties. Do you think that's not necessary?
I think it could be a good idea to add the configuration examples to the build scripts but comment them out.
In other words, I wouldn't turn on any of the power features in those example apps. 馃槈
Now that I think about it, it's not that crucial and cannot be done before we release RC3... Thus, I'll remove that item from Deliverables for now.
Fixed in #1029.
Most helpful comment
I'm in favor of both the alternative proposals for Gradle and Maven.
Thanks, @sbrannen! 馃憤