Conditional Test Execution

There is a newer version available.
For the latest stable release, please see JUnit 6.1.3!

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 @TestOnMac annotation in the @EnabledOnOs demo shows how you can combine @Test and @EnabledOnOs in a single, reusable annotation.

Conditional annotations in JUnit Jupiter are not @Inherited. Consequently, if you wish to apply the same semantics to subclasses, each conditional annotation must be redeclared on each subclass.

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 org.junit.jupiter.api.condition package.

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.

Conditional execution based on operating system
  • Java

  • Kotlin

@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(MAC)
fun onlyOnMacOs() {
    // ...
}

@TestOnMac
fun testOnMac() {
    // ...
}

@Test
@EnabledOnOs(LINUX, MAC)
fun onLinuxOrMac() {
    // ...
}

@Test
@DisabledOnOs(WINDOWS)
fun notOnWindows() {
    // ...
}

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@Test
@EnabledOnOs(MAC)
annotation class TestOnMac
Conditional execution based on architecture
  • Java

  • Kotlin

@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() {
	// ...
}
@Test
@EnabledOnOs(architectures = ["aarch64"])
fun onAarch64() {
    // ...
}

@Test
@DisabledOnOs(architectures = ["x86_64"])
fun notOnX86_64() {
    // ...
}

@Test
@EnabledOnOs(value = [MAC], architectures = ["aarch64"])
fun onNewMacs() {
    // ...
}

@Test
@DisabledOnOs(value = [MAC], architectures = ["aarch64"])
fun 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.

  • Java

  • Kotlin

@Test
@EnabledOnJre(JAVA_17)
void onlyOnJava17() {
	// ...
}

@Test
@EnabledOnJre({ JAVA_17, JAVA_21 })
void onJava17And21() {
	// ...
}

@Test
@EnabledForJreRange(min = JAVA_21, max = JAVA_25)
void fromJava21To25() {
	// ...
}

@Test
@EnabledForJreRange(min = JAVA_21)
void onJava21ndHigher() {
	// ...
}

@Test
@EnabledForJreRange(max = JAVA_18)
void fromJava17To18() {
	// ...
}

@Test
@DisabledOnJre(JAVA_19)
void notOnJava19() {
	// ...
}

@Test
@DisabledForJreRange(min = JAVA_17, max = JAVA_17)
void notFromJava17To19() {
	// ...
}

@Test
@DisabledForJreRange(min = JAVA_19)
void notOnJava19AndHigher() {
	// ...
}

@Test
@DisabledForJreRange(max = JAVA_18)
void notFromJava17To18() {
	// ...
}
@Test
@EnabledOnJre(JAVA_17)
fun onlyOnJava17() {
    // ...
}

@Test
@EnabledOnJre(JAVA_17, JAVA_21)
fun onJava17And21() {
    // ...
}

@Test
@EnabledForJreRange(min = JAVA_21, max = JAVA_25)
fun fromJava21To25() {
    // ...
}

@Test
@EnabledForJreRange(min = JAVA_21)
fun onJava21ndHigher() {
    // ...
}

@Test
@EnabledForJreRange(max = JAVA_18)
fun fromJava17To18() {
    // ...
}

@Test
@DisabledOnJre(JAVA_19)
fun notOnJava19() {
    // ...
}

@Test
@DisabledForJreRange(min = JAVA_17, max = JAVA_17)
fun notFromJava17To19() {
    // ...
}

@Test
@DisabledForJreRange(min = JAVA_19)
fun notOnJava19AndHigher() {
    // ...
}

@Test
@DisabledForJreRange(max = JAVA_18)
fun notFromJava17To18() {
    // ...
}

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, when JUnit Jupiter 5.12 was released the JRE enum defined 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.