1. Overview
1.概述
In this tutorial, we’re going to take a look at conditional test execution with annotations in JUnit 5.
在本教程中,我们将看看在JUnit 5中使用注释的条件测试执行。
These annotations are from the JUnit Jupiter library’s condition package and allow us to specify different types of conditions under which our tests should or should not run.
这些注释来自JUnit Jupiter 库的condition包,允许我们指定不同类型的条件,在这些条件下我们的测试应该或不应该运行。
2. Operating System Conditions
2.操作系统条件
Sometimes, we need to change our test scenarios depending on the operating systems (OS) they’re running on. In these cases, the @EnabledOnOs annotation comes in handy.
有时,我们需要根据所运行的操作系统(OS)来改变我们的测试场景。在这种情况下,@EnabledOnOs注解就会派上用场。
The usage of @EnabledOnOs is simple – we just need to give it a value for the OS type. Furthermore, it also accepts an array argument for when we want to target multiple operating systems.
@EnabledOnOs的用法很简单,我们只需要给它一个操作系统类型的值。此外,它还接受一个数组参数,以便在我们想针对多个操作系统时使用。
For example, let’s say we want to enable a test to run only on Windows and macOS:
例如,假设我们想让一个测试只在Windows和MacOS上运行。
@Test
@EnabledOnOs({OS.WINDOWS, OS.MAC})
public void shouldRunBothWindowsAndMac() {
//...
}
Now, in contrast to the @EnabledOnOs, there is @DisabledOnOs. As the name implies, it disables tests according to the OS type argument:
现在,与@EnabledOnOs相比,有@DisabledOnOs。顾名思义,它根据操作系统类型参数来禁用测试。
@Test
@DisabledOnOs(OS.LINUX)
public void shouldNotRunAtLinux() {
//...
}
3. Java Runtime Environment Conditions
3.Java运行时环境条件
We can also target our tests to run on specific JRE versions using the @EnableOnJre and @DisableOnJre annotations. These annotations also accept an array to enable or disable multiple Java versions:
我们还可以使用@EnableOnJre和@DisableOnJre注解将我们的测试定位在特定的JRE版本上运行。这些注解也接受一个数组来启用或禁用多个Java版本。
@Test
@EnabledOnJre({JRE.JAVA_10, JRE.JAVA_11})
public void shouldOnlyRunOnJava10And11() {
//...
}
As of JUnit 5.6, we can use @EnabledForJreRange to enable a test for a specific range of Java versions:
从JUnit 5.6开始,我们可以使用@EnabledForJreRange来为特定范围的Java版本启用测试。
@Test
@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_13)
public void shouldOnlyRunOnJava8UntilJava13() {
// this test will only run on Java 8, 9, 10, 11, 12, and 13.
}
By default the min value is JAVA_8 and the max value is the maximum possible JRE version. There is also a @DisabledForJreRange to disable a test for a specific range of Java versions:
默认情况下,最小值是JAVA_8,最大值是最大可能的JRE版本。还有一个@DisabledForJreRange可以禁用特定范围的Java版本的测试。
@Test
@DisabledForJreRange(min = JRE.JAVA_14, max = JRE.JAVA_15)
public void shouldNotBeRunOnJava14AndJava15() {
// this won't run on Java 14 and 15.
}
Moreover, if we want to disable our tests running with Java versions other than 8, 9, 10, and 11, we can use the JRE.OTHER enum property:
此外,如果我们想禁止我们的测试在8、9、10和11以外的Java版本下运行,我们可以使用JRE.OTHER enum属性。
@Test
@DisabledOnJre(JRE.OTHER)
public void thisTestOnlyRunsWithUpToDateJREs() {
// this test will only run on Java 8, 9, 10, and 11.
}
4. System Property Conditions
4.系统属性条件
Now, if we want to enable our tests based on JVM system properties, we can use the @EnabledIfSystemProperty annotation.
现在,如果我们想根据JVM系统属性启用我们的测试,我们可以使用@EnabledIfSystemProperty注解。
To use it, we must provide named and matches arguments. The named argument is used to specify an exact system property. The matches is used for defining the pattern of property value with a regular expression.
为了使用它,我们必须提供named和matches参数。named参数用于指定一个精确的系统属性。matches用于用正则表达式来定义属性值的模式。
For instance, let’s say we want to enable a test to run only when the virtual machine vendor name starts with “Oracle”:
例如,假设我们想让一个测试只在虚拟机供应商名称以 “Oracle “开头时运行。
@Test
@EnabledIfSystemProperty(named = "java.vm.vendor", matches = "Oracle.*")
public void onlyIfVendorNameStartsWithOracle() {
//...
}
Likewise, we have the @DisabledIfSystemProperty to disable tests based on JVM system properties. To demonstrate this annotation, let’s take a look at an example:
同样地,我们有@DisabledIfSystemProperty来根据JVM系统属性禁用测试。为了演示这个注解,让我们看看一个例子。
@Test
@DisabledIfSystemProperty(named = "file.separator", matches = "[/]")
public void disabledIfFileSeperatorIsSlash() {
//...
}
5. Environment Variable Conditions
5.环境变量条件
We can also specify environment variable conditions for our tests with @EnabledIfEnvironmentVariable and @DisabledIfEnvironmentVariable annotations.
我们还可以用@EnabledIfEnvironmentVariable和@DisabledIfEnvironmentVariable注解为我们的测试指定环境变量条件。
And, just like the annotations for system property conditions, these annotations take two arguments — named and matches — for specifying the environment variable name and regular expression to match against environment variable values:
而且,就像系统属性条件的注解一样,这些注解需要两个参数 – named和matches –,用于指定环境变量名称和正则表达式以匹配环境变量值。
@Test
@EnabledIfEnvironmentVariable(named = "GDMSESSION", matches = "ubuntu")
public void onlyRunOnUbuntuServer() {
//...
}
@Test
@DisabledIfEnvironmentVariable(named = "LC_TIME", matches = ".*UTF-8.")
public void shouldNotRunWhenTimeIsNotUTF8() {
//...
}
Furthermore, we can consult one of our other tutorials to learn more about system properties and system environment variables.
此外,我们可以参考我们的其他教程,以了解更多关于系统属性和系统环境变量的知识。
6. Script-Based Conditions
6.基于脚本的条件
6.1. Deprecation Notice
6.1.弃用通知
Script-based condition APIs and their implementations were deprecated in JUnit 5.5 and removed from JUnit 5.6. In order to achieve the same result, it’s highly recommended to use a combination of built-in conditions or create a custom implementation of ExecutionCondition.
基于脚本的条件API及其实现在JUnit 5.5中被弃用,并从JUnit 5.6中删除。为了达到同样的效果,强烈建议使用内置条件的组合或创建ExecutionCondition.的自定义实现。
6.2. Conditions
6.2.条件
Prior to JUnit 5.6, we can specify our test’s running conditions by writing scripts within @EnabledIf and @DisabledIf annotations.
在JUnit 5.6之前,我们可以通过在@EnabledIf和@DisabledIf注解中编写脚本来指定我们测试的运行条件。
These annotations accept three arguments:
这些注释接受三个参数。
- value – contains the actual script to run.
- engine (optional) – specifies the scripting engine to use; the default is Oracle Nashorn.
- reason (optional) – for logging purposes, specifies the message JUnit should print if our test fails.
So, let’s see a simple example where we specify only a one-line script, without additional arguments on the annotation:
所以,让我们看一个简单的例子,我们只指定一个单行脚本,在注释上没有附加参数。
@Test
@EnabledIf("'FR' == systemProperty.get('user.country')")
public void onlyFrenchPeopleWillRunThisMethod() {
//...
}
Also, the usage of @DisabledIf is exactly the same:
另外,@DisabledIf的用法完全相同。
@Test
@DisabledIf("java.lang.System.getProperty('os.name').toLowerCase().contains('mac')")
public void shouldNotRunOnMacOS() {
//...
}
Furthermore, we can write multi-line scripts with the value argument.
此外,我们可以用value argument编写多行脚本。
Let’s write a brief example to check the month’s name before running the test.
让我们写一个简单的例子,在运行测试之前检查一下月份的名称。
We’ll define a sentence for reason with supported placeholders:
我们将为reason定义一个句子,支持占位符。
- {annotation} – the string for representing annotation instance.
- {script} – the script text that evaluated inside value argument.
- {result} – the string for representing the return value of the evaluated script.
For this instance, we will have a multi-line script in the value argument and values for engine and reason:
在这个例子中,我们将在value参数中设置一个多行脚本,并为engine和reason设置值。
@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() {
//...
}
We can use several script bindings when writing our scripts:
在编写脚本时,我们可以使用几种脚本绑定方式。
- systemEnvironment – to access system environment variables.
- systemProperty – to access system property variables.
- junitConfigurationParameter – to access configuration parameters.
- junitDisplayName – test or container display name.
- junitTags – to access tags on tests or container.
- anotherUniqueId – to get the unique id of test or container.
Finally, let’s look at another example to see how to use scripts with bindings:
最后,让我们看看另一个例子,看看如何使用带绑定的脚本。
@Test
@DisabledIf("systemEnvironment.get('XPC_SERVICE_NAME') != null" +
"&& systemEnvironment.get('XPC_SERVICE_NAME').contains('intellij')")
public void notValidForIntelliJ() {
//this method will not run on intelliJ
}
Moreover, please consult one of our other tutorials to learn more about @EnabledIf and @DisabledIf annotations.
此外,请参考我们的其他教程,以了解更多关于 @EnabledIf和 @DisabledIf注释的内容。
7. Creating Custom Conditional Annotations
7.创建自定义条件注解
A very powerful feature that comes with JUnit 5 is the ability to create custom annotations. We can define custom conditional annotations by using a combination of existing conditional annotations.
JUnit 5附带的一个非常强大的功能是创建自定义注释的能力。我们可以通过使用现有条件注释的组合来定义自定义条件注释。
For instance, suppose we want to define all our tests to run for specific OS types with specific JRE versions. We can write a custom annotation for this:
例如,假设我们想定义所有的测试,使其在特定的操作系统类型和特定的JRE版本下运行。我们可以为此写一个自定义注解。
@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() {
// this method will run with Java9, 10, 11 and Linux or macOS.
}
Furthermore, we can use script-based annotations to create a custom annotation:
此外,我们可以使用基于脚本的注释来创建一个自定义注释。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@DisabledIf("Math.random() >= 0.5")
@interface CoinToss {
}
@RepeatedTest(2)
@CoinToss
public void gamble() {
// this method run run roughly 50% of the time
}
8. Conclusion
8.结语
In this article, we learned about conditional test execution with annotations in JUnit 5. Also, we walked through some examples of their usage.
在这篇文章中,我们了解了JUnit 5中使用注解的条件测试执行。此外,我们还浏览了一些使用的例子。
Next, we saw how to create custom conditional annotations.
接下来,我们看到了如何创建自定义的条件注释。
To learn more about this topic, we can consult JUnit’s documentation about conditional test execution with annotations.
要了解有关这一主题的更多信息,我们可以查阅JUnit关于使用注释的条件测试执行的文档。
As usual, all the example code for this article can be found over on GitHub.
像往常一样,本文的所有示例代码都可以在GitHub上找到。