后端——框架——测试框架——junit——条件
本篇包含三个部分。
第一部分,介绍Junit与条件相关的API,它的根接口为ExecutionCondition,每一种注解都有对应的Condition实现类,例如@DisabledIf对应DisabledIfCondition。
第二部分,研究源码,以BooleanExecutionCondition为例。
第三部分,配置,与listener类似,也是XX.deactivate。
1. API
1.1 ExecutionCondition
root根级接口,只有一个方法evaluateExecutionCondition。
方法的参数类型为ExtensionContext,它表示执行的上下文。
方法的返回值类型为ConditionEvaluationResult。
ConditionEvaluation对象有两个属性,一个是enabled,含义是测试案例能否执行。另外一个是reason,含义是执行的原因,通常在无法执行时,才设置该值。
1.2 MethodBaseCondition
根据方法(注解中的methodName)的返回值判断是否执行测试案例,返回值必须是布尔类型。根据方法(注解中的disabledReasoned)的生成禁用原因,返回值必须是字符串。
它有三个属性,
annotationType,含义是添加在测试案例上的注解类型,例如@DisabledIf。
methoName,含义是判断方法,它指定方法的名称,返回值必须是布尔类型。它的源码
如下:protected abstract boolean isEnabled(boolean var1); 它的参数,就是方法的返回值。
customDisableReason,含义是能或否的原因,它指定方法的名称,返回值必须是字符串类型。
String customReason = (String)this.customDisabledReason.apply(annotation); return customReason.isEmpty() ? ConditionEvaluationResult.disabled(defaultReason) : ConditionEvaluationResult.disabled(customReason);
方法的返回值会被强制转换为String类型。
它的实现类有两个:DisabledIfCondition,EnabledIfCondition。
1.3 DisabledCondition
根据测试案例上是否存在@Disabled注解来判断,存在则禁用。
1.4 BooleanExecutionCondition
根据注解中的信息计算出一个布尔值,若布尔值为false,需要给出原因。子类实现isEnabled(Annotation),它的返回值是布尔类型。
它有四个属性。
annotationType,表示注解的类型。
enabledReason,表示启用的原因,类型为字符串。
disabledReason,表示禁用的原因,类型为字符串。
customDisabledReason,表示禁用的原因,类型为Function。
它的实现类有:
EnabledOnOsCondition, DisabledOnOsCondition。
EnabledOnJreCondition, DisabledOnJreCondition。
EnabledForJreRangeCondition, DisabledOnJreCondition。
它很适合扩展,下述在演示示例会继承此类。对应的注解名称,去除Condition后缀即可。
1.5 abstractRepeatableAnnotationCondition
根据注解的信息返回一个ConditionEvaluationResult对象,注解的类型必须是@Repetable。源码如下:
AnnotationUtils.findRepeatableAnnotations(annotatedElement, this.annotationType).stream()
若不是@Repetable注解,findRepeatableAnnotations会抛错。
它只有一个属性,annotationType,个人感觉与BooleanExecutionCondition区别不大,它只是将布尔值,reason相关的信息封装为ConditionEvaluationResult对象。
它的实现类有:
EnabledIfEnvironmentVariableCondition, DisabledIfEnvironmentVariableCondition。
EnabledIfSystemPropertyCondition,DisabledIfSystemPropertyCondition。
2. 源码研究
以BooleanExecutionCondition为例:
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { return (ConditionEvaluationResult)AnnotationUtils
.findAnnotation(context.getElement(), this.annotationType).map((annotation) -> { return this.isEnabled(annotation) ? ConditionEvaluationResult.enabled(this.enabledReason) : ConditionEvaluationResult.disabled(this.disabledReason, (String)this.customDisabledReason.apply(annotation)); }).orElseGet(this::enabledByDefault); }
第一步,调用findAnnotation,开启流,将测试案例上的注解作为流的参数。
第二步,调用isEnabled方法,它返回值为布尔类型,由具体的子类实现。
第三步,若方法返回true,则调用ConditionEvaluationResult.enabled方法,参数为注解的enabledReason属性值,否则调用ConditionEvaluationResult.disabled方法,参数为注解的disabledReason属性值, 它的类型为Function,调用属性值同名的函数。
第四步,若findAnnotation无返回值,获取默认值,调用enabledByDefault方法。
3. 忽略规则
默认情况下,所有的ExecutionCondition都会生效,可以通过配置junit.jupiter.conditions.deactivate忽略某些规则,它的值为ExecutionCondition中的实现类。例如org.junit.*DisabledCondition。