如何测试扩展实现

时间:2017-10-20 01:43:16

标签: junit5

JUnit 5 API中有几个扩展点。

例如:

几乎所有这些扩展程序都采用某种形式的ExtensionContext,可以访问test classtest methodtest instancepublish report entries的能力,{{ 3}}和其他功能。其中很多都直接在类实例上运行

大多数实现可能会使用store valuesreflection using ReflectionSupport的某种组合,它们都是静态方法,这使得它们很难被模拟。

现在,我已经编写了ExecutionCondition的实现,或者实现了BeforeEachCallbackAfterEachCallback的扩展程序 - 我如何有效地测试它们?

我想我可以模仿ExtensionContext,但这似乎不是一种有效运用不同代码路径的好方法。

在JUnit的内部,有annotation discovery using AnnotationSupport,它与ExecutionEventRecorder一起用于选择和执行测试,然后是JupiterTestEngine implementation for execution (which is @API(status=INTERNAL))

由于publicJupiterTestEngine的可见度,我可以使用相同的模式。

以下是一些具体的例子来说明:

  1. ExecutionCondition,可根据系统属性启用测试。这可以通过一些反射进行测试,并使用@BeforeEach@AfterEach样式中的perform assertions on the resulting events进行测试,但是当并行测试执行到来时,处理和可能出现的问题似乎更复杂。这个例子展示了一个例子"我如何提供一个真实的ExtensionContext并断言结果"。

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @ExtendWith(SystemPropertyCondition.class)
    public @interface SystemProperty {
      String key();
      String value();
    }
    
    public class SystemPropertyCondition implements ExecutionCondition {
      @Override
      public ConditionEvaluationResult evaluateExecutionCondition(final ExtensionContext context) {
        return context.getTestMethod()
            .flatMap(element -> AnnotationSupport.findAnnotation(element, SystemProperty.class))
            .map(systemProperty -> {
              if (systemProperty.value().equals(System.getProperty(systemProperty.key()))) {
                return ConditionEvaluationResult.enabled("Property is available");
              } else {
                return ConditionEvaluationResult.disabled("Property not equal");
              }
            })
            .orElseGet(() -> ConditionEvaluationResult.enabled("No annotations"));
      }
    }
    
  2. 仅在一周中提供的某一天运行的ExecutionCondition。如何注入测试时钟?您如何测试条件是否是预期结果?我想一些状态/实现可以放在TestInfo中,这允许在扩展之间传递某种状态(比如使用BeforeEachCallback,这可能是正确的路径,但那是将依赖于扩展程序执行的顺序。我不相信在BeforeEachCallback之前调用ExecutionCondition,因此该路径可能不是正确的。此示例显示了&#34 ;我如何注入依赖项"并且还显示与上一个提供ExtensionContext并在结果上断言的示例相同的问题。

    @ExtendWith(RunOnDayCondition.class)
    public @interface RunOnDay {
      DayOfWeek[] value();
    }
    
    final class RunOnDayCondition implements ExecutionCondition {
    
      private static final ConditionEvaluationResult DEFAULT = disabled(
          RunOnDay.class + " is not present"
      );
    
      @Override
      public ConditionEvaluationResult evaluateExecutionCondition(final ExtensionContext context) {
        return context.getElement()
            .flatMap(annotatedElement -> findAnnotation(annotatedElement, RunOnDay.class))
            .map(RunOnDay::value)
            .map(RunOnDayCondition::evaluateIfRunningOnDay)
            .orElse(DEFAULT);
      }
    
      private static ConditionEvaluationResult evaluateIfRunningOnDay(final DayOfWeek[] days) {
        // TODO: How would you inject a test clock?
        final DayOfWeek currentDay = LocalDate.now().getDayOfWeek();
        final boolean runningInday = Stream.of(days).anyMatch(currentDay::equals);
    
        if (runningInday) {
          return enabled("Current day is " + currentDay + ", in the specified days of " + Arrays.toString(days));
        } else {
          return disabled("Current day is " + currentDay + ", not in the specified days of " + Arrays.toString(days));
        }
      }
    }
    
  3. 设置临时目录的扩展,将其作为参数提供,然后在测试后清除它。这将使用ParameterResolverBeforeEachCallbackAfterEachCallbackExtensionContext.Store。此示例显示扩展实现可能使用多个扩展点,并可以使用存储来跟踪状态。

  4. 扩展测试的自定义测试引擎是否是正确的方法?

    那么,如何在不依赖内部API且没有"复制"努力进入嘲笑?

2 个答案:

答案 0 :(得分:1)

我知道这不是一个完整的答案(但我现在在移动设备上,你的问题非常复杂)...但是试试吧 this project可以帮到你。

如果你稍微限制一下我的问题,我可以尝试更好地帮助你

答案 1 :(得分:0)

JUnit 5.4 起,您可以使用Test Kit测试扩展。该功能似乎在 JUnit 5.7 中变得稳定。 (请注意,API在这些版本之间已更改。)

使用测试套件,您可以在实际测试中执行模拟测试,并对结果执行断言。请注意,您可能需要防止您的模拟测试被直接发现。 Issue #1779 of JUnit 5可能会帮助您。