后端——框架——测试框架——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。

相关