写点什么

原创 | TDD 工具集:JUnit、AssertJ 和 Mockito (十六) 编写测试 - 有条件执行测试

发布于: 2020 年 06 月 03 日
原创 | TDD工具集:JUnit、AssertJ和Mockito (十六)编写测试-有条件执行测试





重要性:★★★☆☆



JUnit Jupiter通过ExecutionCondition扩展API允许开发者根据各种条件编程式地生效或失效某些测试。最简单的条件执行例子是通过内建的DisabledCondition支持@Disabled注解。除了@Disabled之外,JUnit Jupiter还在org.junit.jupiter.api.condition包中提供了一些基于注解的执行条件,开发人员可以使用它们来声明式地生效或失效测试或测试容器(测试类等)。



如果注册了多个ExecutionCondition,只要其中任何一个条件返回了disabled,测试或测试容器就会被失效掉。



下文将要介绍的这些条件注解也可以作为元注解用来创建定制的组合注解。



下文将要介绍的所有条件注解,都可以用来注解测试方法、测试类和测试接口。



除非特别说明,下面介绍的每一个条件注解在一个测试接口、测试类或测试方法中只能声明一次。如果同一个条件注解(不论起属性值是否相同)直接、间接或以元注解的方式在一个给定的元素(测试方法、测试类、测试接口)上多次出现,JUnit将只使用它遇到的第一个注解,其他的同种条件注解将被默默地忽略掉。但是,每个条件注解都可以和org.junit.jupiter.api.condition包中的其它条件注解联合使用。



例如,在下面的测试方法onlyOnMacOs()中,注解@EnabledOnOs出现了两次,虽然它们的值不同,但最终只有其中一个会起作用,最终只有两个有效注解生效:@EnabledOnOs(MAC)和@EnabledOnJre(JAVA_8),@EnabledOnOs(LINUX)注解被直接忽略掉了。

@Test
@EnabledOnOs(MAC)
@EnabledOnOs(LINUX)
@EnabledOnJre(JAVA_8)
void onlyOnMacOs() {
// ...
}

下面介绍一些常用的条件注解。



1. 操作系统条件

根据测试执行时所处的操作系统生效/失效测试。



有两个和操作系统相关的注解:@EnabledOnOs在操作系统符合条件时生效测试,@DisabledOnOs在操作系统符合条件时失效测试。

package yang.yu.tdd.conditions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.EnabledOnOs;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static org.junit.jupiter.api.condition.OS.*;
public class OsCondition {
@Test
@EnabledOnOs(MAC)
void onlyOnMacOs() {
System.out.println("Run on Mac");
}
@TestOnMac
void testOnMac() {
System.out.println("Run on Mac");
}
@Test
@EnabledOnOs({ LINUX, MAC })
void onLinuxOrMac() {
System.out.println("Run on Linux or Mac");
}
@Test
@DisabledOnOs(WINDOWS)
void notOnWindows() {
System.out.println("Not Run on Windows");
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@EnabledOnOs(MAC)
@interface TestOnMac {
}
}

上面的示例代码中,我们还定义了一个组合条件注解@TestOnMac



2. Java版本条件

根据测试执行时的Java运行时版本生效/失效测试。相关的注解可分为两组:



@EnabledOnJre@DisabledOnJre在Java版本等于指定的版本号时生效或失效测试;



@EnabledForJreRange 和 @DisabledForJreRange 在Java版本处于指定的版本范围时生效或失效测试。范围的缺省下限是JRE.JAVA_8,缺省上限是JRE.OTHER,允许使用半开区间,即可以只指定minmax其中之一。

package yang.yu.tdd.conditions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledForJreRange;
import org.junit.jupiter.api.condition.DisabledOnJre;
import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.EnabledOnJre;
import static org.junit.jupiter.api.condition.JRE.*;
public class JavaCondition {
@Test
@EnabledOnJre(JAVA_8)
void onlyOnJava8() {
System.out.println("Run on Java 8");
}
@Test
@EnabledOnJre({ JAVA_9, JAVA_10 })
void onJava9Or10() {
System.out.println("Run on Java 9 or 10");
}
@Test
@EnabledForJreRange(min = JAVA_9, max = JAVA_11)
void fromJava9to11() {
System.out.println("Run on Java 9 to 11");
}
@Test
@EnabledForJreRange(min = JAVA_9)
void fromJava9toCurrentJavaFeatureNumber() {
System.out.println("Run on Java 9 or above");
}
@Test
@EnabledForJreRange(max = JAVA_11)
void fromJava8To11() {
System.out.println("Run on Java 11 or below");
}
@Test
@DisabledOnJre(JAVA_9)
void notOnJava9() {
System.out.println("Run on Java not 9");
}
@Test
@DisabledForJreRange(min = JAVA_9, max = JAVA_11)
void notFromJava9to11() {
System.out.println("Run on Java not between 9 to 11");
}
@Test
@DisabledForJreRange(min = JAVA_9)
void notFromJava9toCurrentJavaFeatureNumber() {
System.out.println("Run on Java not above 9");
}
@Test
@DisabledForJreRange(max = JAVA_11)
void notFromJava8to11() {
System.out.println("Run on Java not below 11");
}
}



3. 系统属性条件

根据测试执行时的JVM的系统属性值生效或失效测试。



有两个和系统属性相关的条件注解:@EnabledIfSystemProperty@DisabledIfSystemProperty。这些注解有两个属性:named属性和matches属性,其中matches属性是一个正则表达式。如果存在named属性指定的属性名并且属性值与matches属性匹配,则分别生效/失效这两个注解所标识的测试方法、测试类或测试接口。



这两个注解都是可重复的,意味着可以在同一个元素(测试方法、测试类、测试接口等)上多次声明@EnabledIfSystemProperty@DisabledIfSystemProperty注解(注解的属性值可以相同,也可以不同)。这些注解可以直接、间接存在,或者以元注解的方式存在。



除此以外还有两个注解@EnabledIfSystemProperties@DisabledIfSystemProperties,分别用于组合多个@EnabledIfSystemProperty@DisabledIfSystemProperty注解。

package yang.yu.tdd.conditions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class SysPropCondition {
@Test
@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")
void onlyOn64BitArchitectures() {
// ...
}
@Test
@DisabledIfSystemProperty(named = "ci-server", matches = "true")
void notOnCiServer() {
// ...
}
@Test
@EnabledIfSystemProperties({
@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*"),
@EnabledIfSystemProperty(named = "ci-server", matches = "true")
})
void multiEnabledIfSystemProperties() {
// ...
}
@Test
@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")
@EnabledIfSystemProperty(named = "ci-server", matches = "true")
void multiEnabledIfSystemProperties2() {
// ...
}
@Test
@DisabledIfSystemProperties({
@DisabledIfSystemProperty(named = "os.arch", matches = ".*64.*"),
@DisabledIfSystemProperty(named = "ci-server", matches = "true")
})
void multiDisabledIfSystemProperties() {
// ...
}
@Test
@DisabledIfSystemProperty(named = "os.arch", matches = ".*64.*")
@DisabledIfSystemProperty(named = "ci-server", matches = "true")
void multiDisabledIfSystemProperties2() {
// ...
}
@Test
@EnabledIfOsArch64
void onlyOn64BitArchitectures2() {
// ...
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")
@interface EnabledIfOsArch64 {
}
}



4. 环境变量条件

根据环境变量的值生效/失效测试。



有两个和环境变量相关的注解:@EnabledIfEnvironmentVariable@DisabledIfEnvironmentVariable注解。这些注解有两个属性:named属性和matches属性,其中matches属性是一个正则表达式。如果存在named属性指定的环境变量名名并且环境变量值与matches属性匹配,则生效/失效这两个注解所标识的测试方法、测试类或测试接口。



这两个注解都是可重复的,意味着可以在同一个元素(测试方法、测试类、测试接口等)上多次声明@EnabledIfEnvironmentVariable@DisabledIfEnvironmentVariable注解(注解的属性值可以相同,也可以不同)。这些注解可以直接、间接存在,或者以元注解的方式存在。



除此以外还有两个注解@EnabledIfEnvironmentVariables@DisabledIfEnvironmentVariables,分别用于组合多个@EnabledIfEnvironmentVariable@DisabledIfEnvironmentVariable注解。

package yang.yu.tdd.conditions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class EnvVariableCondition {
@Test
@EnabledIfEnvironmentVariable(named = "ENV", matches = "staging-server")
void onlyOnStagingServer() {
// ...
}
@Test
@DisabledIfEnvironmentVariable(named = "ENV", matches = ".*development.*")
void notOnDeveloperWorkstation() {
// ...
}
@Test
@EnabledIfEnvironmentVariables({
@EnabledIfEnvironmentVariable(named = "ENV", matches = "staging-server"),
@EnabledIfEnvironmentVariable(named = "DB", matches = "mysql")
})
void enableMultiEnvironmentVariables() {
// ...
}
@Test
@EnabledIfEnvironmentVariable(named = "ENV", matches = "staging-server")
@EnabledIfEnvironmentVariable(named = "DB", matches = "mysql")
void enableMultiEnvironmentVariables2() {
// ...
}
@Test
@DisabledIfEnvironmentVariables({
@DisabledIfEnvironmentVariable(named = "ENV", matches = "staging-server"),
@DisabledIfEnvironmentVariable(named = "DB", matches = "mysql")
})
void disableMultiEnvironmentVariables() {
// ...
}
@Test
@DisabledIfEnvironmentVariable(named = "ENV", matches = "staging-server")
@DisabledIfEnvironmentVariable(named = "DB", matches = "mysql")
void disableMultiEnvironmentVariables2() {
// ...
}
@Test
@EnabledIfDevEnv
void onlyOnDevEnvironment() {
// ...
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@EnabledIfEnvironmentVariable(named = "ENV", matches = "dev")
@interface EnabledIfDevEnv {
}
}



这一节我们就分享到这里,下一节我们讲“编写测试的标签和过滤”







发布于: 2020 年 06 月 03 日阅读数: 65
用户头像

高级架构师,技术顾问,交流公号:编程道与术 2020.04.28 加入

杨宇于2020年创立编程道与术,致力于研究领域分析与建模、测试驱动开发、架构设计、自动化构建和持续集成、敏捷开发方法论、微服务、云计算等顶尖技术领域。 了解更多公众号:编程道与术

评论

发布
暂无评论
原创 | TDD工具集:JUnit、AssertJ和Mockito (十六)编写测试-有条件执行测试