Conditional Test Execution
The ExecutionCondition extension API in JUnit Jupiter allows
developers to either enable or disable a test class or test method based on certain
conditions programmatically. The simplest example of such a condition is the built-in
DisabledCondition which supports the @Disabled annotation (see
Disabling Tests).
In addition to @Disabled, JUnit Jupiter also supports several other annotation-based
conditions in the org.junit.jupiter.api.condition package that allow developers to
enable or disable test classes and test methods declaratively. If you wish to provide
details about why they might be disabled, every annotation associated with these built-in
conditions has a disabledReason attribute available for that purpose.
When multiple ExecutionCondition extensions are registered, a test class or test method
is disabled as soon as one of the conditions returns disabled. If a test class is
disabled, all test methods within that class are automatically disabled as well. If a test
method is disabled, that prevents execution of the test method and method-level lifecycle
callbacks such as @BeforeEach methods, @AfterEach methods, and corresponding extension
APIs. However, that does not prevent the test class from being instantiated, and it does
not prevent the execution of class-level lifecycle callbacks such as @BeforeAll methods,
@AfterAll methods, and corresponding extension APIs.
See ExecutionCondition and the following sections for
details.
|
Composed Annotations
Note that any of the conditional annotations listed in the following sections may also
be used as a meta-annotation in order to create a custom composed annotation. For
example, the |
|
Conditional annotations in JUnit Jupiter are not |
|
Unless otherwise stated, each of the conditional annotations listed in the following
sections can only be declared once on a given test interface, test class, or test method.
If a conditional annotation is directly present, indirectly present, or meta-present
multiple times on a given element, only the first such annotation discovered by JUnit will
be used; any additional declarations will be silently ignored. Note, however, that each
conditional annotation may be used in conjunction with other conditional annotations in
the |
Operating System and Architecture Conditions
A container or test may be enabled or disabled on a particular operating system,
architecture, or combination of both via the @EnabledOnOs and @DisabledOnOs
annotations.
@Test
@EnabledOnOs(MAC)
void onlyOnMacOs() {
// ...
}
@TestOnMac
void testOnMac() {
// ...
}
@Test
@EnabledOnOs({ LINUX, MAC })
void onLinuxOrMac() {
// ...
}
@Test
@DisabledOnOs(WINDOWS)
void notOnWindows() {
// ...
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@EnabledOnOs(MAC)
@interface TestOnMac {
}
@Test
@EnabledOnOs(architectures = "aarch64")
void onAarch64() {
// ...
}
@Test
@DisabledOnOs(architectures = "x86_64")
void notOnX86_64() {
// ...
}
@Test
@EnabledOnOs(value = MAC, architectures = "aarch64")
void onNewMacs() {
// ...
}
@Test
@DisabledOnOs(value = MAC, architectures = "aarch64")
void notOnNewMacs() {
// ...
}
Java Runtime Environment Conditions
A container or test may be enabled or disabled on particular versions of the Java Runtime
Environment (JRE) via the @EnabledOnJre and @DisabledOnJre annotations or on a
particular range of versions of the JRE via the @EnabledForJreRange and
@DisabledForJreRange annotations. The range effectively defaults to JRE.JAVA_8 as the
lower bound and JRE.OTHER as the upper bound, which allows usage of half open ranges.
The following listing demonstrates the use of these annotations with predefined JRE enum constants.
@Test
@EnabledOnJre(JAVA_17)
void onlyOnJava17() {
// ...
}
@Test
@EnabledOnJre({ JAVA_17, JAVA_21 })
void onJava17And21() {
// ...
}
@Test
@EnabledForJreRange(min = JAVA_9, max = JAVA_11)
void fromJava9To11() {
// ...
}
@Test
@EnabledForJreRange(min = JAVA_9)
void onJava9AndHigher() {
// ...
}
@Test
@EnabledForJreRange(max = JAVA_11)
void fromJava8To11() {
// ...
}
@Test
@DisabledOnJre(JAVA_9)
void notOnJava9() {
// ...
}
@Test
@DisabledForJreRange(min = JAVA_9, max = JAVA_11)
void notFromJava9To11() {
// ...
}
@Test
@DisabledForJreRange(min = JAVA_9)
void notOnJava9AndHigher() {
// ...
}
@Test
@DisabledForJreRange(max = JAVA_11)
void notFromJava8To11() {
// ...
}
Since the enum constants defined in JRE are static for any given JUnit release, you
might find that you need to configure a Java version that is not supported by the JRE
enum. For example, as of JUnit Jupiter 5.12 the JRE enum defines JAVA_25 as the
highest supported Java version. However, you may wish to run your tests against later
versions of Java. To support such use cases, you can specify arbitrary Java versions via
the versions attributes in @EnabledOnJre and @DisabledOnJre and via the minVersion
and maxVersion attributes in @EnabledForJreRange and @DisabledForJreRange.
The following listing demonstrates the use of these annotations with arbitrary Java versions.
@Test
@EnabledOnJre(versions = 26)
void onlyOnJava26() {
// ...
}
@Test
@EnabledOnJre(versions = { 25, 26 })
// Can also be expressed as follows.
// @EnabledOnJre(value = JAVA_25, versions = 26)
void onJava25And26() {
// ...
}
@Test
@EnabledForJreRange(minVersion = 26)
void onJava26AndHigher() {
// ...
}
@Test
@EnabledForJreRange(minVersion = 25, maxVersion = 27)
// Can also be expressed as follows.
// @EnabledForJreRange(min = JAVA_25, maxVersion = 27)
void fromJava25To27() {
// ...
}
@Test
@DisabledOnJre(versions = 26)
void notOnJava26() {
// ...
}
@Test
@DisabledOnJre(versions = { 25, 26 })
// Can also be expressed as follows.
// @DisabledOnJre(value = JAVA_25, versions = 26)
void notOnJava25And26() {
// ...
}
@Test
@DisabledForJreRange(minVersion = 26)
void notOnJava26AndHigher() {
// ...
}
@Test
@DisabledForJreRange(minVersion = 25, maxVersion = 27)
// Can also be expressed as follows.
// @DisabledForJreRange(min = JAVA_25, maxVersion = 27)
void notFromJava25To27() {
// ...
}
Native Image Conditions
A container or test may be enabled or disabled within a
GraalVM native image via the
@EnabledInNativeImage and @DisabledInNativeImage annotations. These annotations are
typically used when running tests within a native image using the Gradle and Maven
plug-ins from the GraalVM Native
Build Tools project.
@Test
@EnabledInNativeImage
void onlyWithinNativeImage() {
// ...
}
@Test
@DisabledInNativeImage
void neverWithinNativeImage() {
// ...
}
System Property Conditions
A container or test may be enabled or disabled based on the value of the named JVM
system property via the @EnabledIfSystemProperty and @DisabledIfSystemProperty
annotations. The value supplied via the matches attribute will be interpreted as a
regular expression.
@Test
@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")
void onlyOn64BitArchitectures() {
// ...
}
@Test
@DisabledIfSystemProperty(named = "ci-server", matches = "true")
void notOnCiServer() {
// ...
}
|
As of JUnit Jupiter 5.6, |
Environment Variable Conditions
A container or test may be enabled or disabled based on the value of the named
environment variable from the underlying operating system via the
@EnabledIfEnvironmentVariable and @DisabledIfEnvironmentVariable annotations. The
value supplied via the matches attribute will be interpreted as a regular expression.
@Test
@EnabledIfEnvironmentVariable(named = "ENV", matches = "staging-server")
void onlyOnStagingServer() {
// ...
}
@Test
@DisabledIfEnvironmentVariable(named = "ENV", matches = ".*development.*")
void notOnDeveloperWorkstation() {
// ...
}
|
As of JUnit Jupiter 5.6, |
Custom Conditions
As an alternative to implementing an ExecutionCondition, a
container or test may be enabled or disabled based on a condition method configured via
the @EnabledIf and @DisabledIf annotations. A condition method must have a boolean
return type and may accept either no arguments or a single ExtensionContext argument.
The following test class demonstrates how to configure a local method named
customCondition via @EnabledIf and @DisabledIf.
@Test
@EnabledIf("customCondition")
void enabled() {
// ...
}
@Test
@DisabledIf("customCondition")
void disabled() {
// ...
}
boolean customCondition() {
return true;
}
Alternatively, the condition method can be located outside the test class. In this case, it must be referenced by its fully qualified name as demonstrated in the following example.
package example;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIf;
class ExternalCustomConditionDemo {
@Test
@EnabledIf("example.ExternalCondition#customCondition")
void enabled() {
// ...
}
}
class ExternalCondition {
static boolean customCondition() {
return true;
}
}
|
There are several cases where a condition method would need to be
In any other case, you can use either static methods or instance methods as condition methods. |
|
It is often the case that you can use an existing static method in a utility class as a custom condition. For example,
|