1. 概述
在本教程中,我们将深入探讨 JUnit 5 中基于注解的条件化测试执行机制。
这些注解来自 JUnit Jupiter 扩展库 的 condition
包,可以让我们根据不同的运行条件来控制测试是否执行。
⚠️ 注意:如果你的测试需要在特定环境、JDK 版本或系统配置下才跑,这些注解就是你的“神器”。
2. 操作系统条件控制
有时候我们需要让测试只在某些操作系统上运行,这时候就可以使用 @EnabledOnOs
注解。
使用方法很简单,只需要传入一个 OS
枚举值即可,也可以传入多个:
@Test
@EnabledOnOs({OS.WINDOWS, OS.MAC})
public void shouldRunBothWindowsAndMac() {
// 只在 Windows 和 macOS 上运行
}
与之对应的是 @DisabledOnOs
,用于禁止在指定系统上运行:
@Test
@DisabledOnOs(OS.LINUX)
public void shouldNotRunAtLinux() {
// 在 Linux 上不运行
}
✅ 适用于不同平台行为差异较大的场景。
3. Java 运行时环境(JRE)条件控制
我们还可以根据 JRE 版本来控制测试是否运行,使用 @EnabledOnJre
和 @DisabledOnJre
注解:
@Test
@EnabledOnJre({JRE.JAVA_10, JRE.JAVA_11})
public void shouldOnlyRunOnJava10And11() {
// 只在 Java 10 和 11 上运行
}
从 JUnit 5.6 开始,新增了范围判断注解:
@Test
@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_13)
public void shouldOnlyRunOnJava8UntilJava13() {
// Java 8 到 13 都可以运行
}
还有一个反向控制的:
@Test
@DisabledForJreRange(min = JRE.JAVA_14, max = JRE.JAVA_15)
public void shouldNotBeRunOnJava14AndJava15() {
// Java 14 和 15 不运行
}
⚠️ 如果你想让测试只在主流版本上运行(比如 8、9、10、11),可以用 JRE.OTHER
:
@Test
@DisabledOnJre(JRE.OTHER)
public void thisTestOnlyRunsWithUpToDateJREs() {
// 只在 Java 8~11 上运行
}
4. 系统属性条件控制
使用 @EnabledIfSystemProperty
可以根据 JVM 系统属性来控制测试执行:
@Test
@EnabledIfSystemProperty(named = "java.vm.vendor", matches = "Oracle.*")
public void onlyIfVendorNameStartsWithOracle() {
// 只在 Oracle JVM 上运行
}
对应地,@DisabledIfSystemProperty
表示不满足条件时禁用:
@Test
@DisabledIfSystemProperty(named = "file.separator", matches = "[/]")
public void disabledIfFileSeperatorIsSlash() {
// 文件分隔符为 / 时不运行(Linux/macOS)
}
5. 环境变量条件控制
类似地,可以使用 @EnabledIfEnvironmentVariable
和 @DisabledIfEnvironmentVariable
来基于环境变量控制测试:
@Test
@EnabledIfEnvironmentVariable(named = "GDMSESSION", matches = "ubuntu")
public void onlyRunOnUbuntuServer() {
// 只在 Ubuntu 桌面环境下运行
}
@Test
@DisabledIfEnvironmentVariable(named = "LC_TIME", matches = ".*UTF-8.")
public void shouldNotRunWhenTimeIsNotUTF8() {
// LC_TIME 不是 UTF-8 格式时不运行
}
💡 如果你对系统属性和环境变量的区别不太清楚,可以参考 Java 中 System.getProperty 与 System.getenv 的区别。
6. GraalVM 原生镜像条件控制
在使用 GraalVM 构建原生镜像时,可以使用以下两个注解控制测试是否在原生镜像环境中运行:
@Test
@EnabledInNativeImage
void shouldOnlyRunWithinNativeImage() {
// 只在原生镜像中运行
}
@Test
@DisabledInNativeImage
void shouldNeverRunWithinNativeImage() {
// 原生镜像中不运行
}
✅ 适用于 Spring Native 或其他需要 GraalVM 原生编译的项目。
7. 脚本驱动条件控制(⚠️ 已废弃)
7.1. 废弃说明
从 JUnit 5.5 开始,脚本驱动的条件注解(如 @EnabledIf
和 @DisabledIf
)被标记为废弃,并在 JUnit 5.6 中移除。
官方建议使用内置条件注解组合,或者自定义 ExecutionCondition
接口实现。
7.2. 脚本条件使用示例(仅适用于 JUnit 5.5 及以下)
虽然已废弃,但为了完整性,我们还是来看一下使用方式:
@Test
@EnabledIf("'FR' == systemProperty.get('user.country')")
public void onlyFrenchPeopleWillRunThisMethod() {
// 只有法国用户运行
}
@Test
@DisabledIf("java.lang.System.getProperty('os.name').toLowerCase().contains('mac')")
public void shouldNotRunOnMacOS() {
// macOS 不运行
}
还可以写多行脚本:
@Test
@EnabledIf(value = {
"load('nashorn:mozilla_compat.js')",
"importPackage(java.time)",
"",
"var thisMonth = LocalDate.now().getMonth().name()",
"var february = Month.FEBRUARY.name()",
"thisMonth.equals(february)"
},
engine = "nashorn",
reason = "On {annotation}, with script: {script}, result is: {result}")
public void onlyRunsInFebruary() {
// 只在二月运行
}
脚本中可以使用的绑定变量包括:
systemEnvironment
– 环境变量systemProperty
– 系统属性junitConfigurationParameter
– 配置参数junitDisplayName
– 显示名称junitTags
– 标签anotherUniqueId
– 唯一 ID
再来一个示例:
@Test
@DisabledIf("systemEnvironment.get('XPC_SERVICE_NAME') != null" +
"&& systemEnvironment.get('XPC_SERVICE_NAME').contains('intellij')")
public void notValidForIntelliJ() {
// IntelliJ IDEA 中不运行
}
⚠️ 虽然灵活,但脚本维护成本高,建议尽量使用内置注解替代。
8. 自定义条件注解
JUnit 5 支持我们创建自定义注解,将多个条件组合起来:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@DisabledOnOs({OS.WINDOWS, OS.SOLARIS, OS.OTHER})
@EnabledOnJre({JRE.JAVA_9, JRE.JAVA_10, JRE.JAVA_11})
@interface ThisTestWillOnlyRunAtLinuxAndMacWithJava9Or10Or11 {
}
@ThisTestWillOnlyRunAtLinuxAndMacWithJava9Or10Or11
public void someSuperTestMethodHere() {
// 只在 Linux/macOS + Java 9~11 上运行
}
甚至可以结合脚本:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@DisabledIf("Math.random() >= 0.5")
@interface CoinToss {
}
@RepeatedTest(2)
@CoinToss
public void gamble() {
// 大约 50% 的概率运行
}
✅ 自定义注解能极大提升代码复用性和可读性。
9. 总结
通过本文,我们了解了 JUnit 5 中各种条件化测试执行的注解,并通过示例展示了它们的使用方法。
我们还介绍了如何创建自定义注解来组合多个条件,从而更好地控制测试执行。
📚 更多详情请参考 JUnit 5 官方文档 - 条件化测试执行
📁 示例代码已上传至 GitHub 仓库