JUnit 5 API中有几个扩展点。
例如:
AfterEachCallback
AfterAllCallback
AfterTestExecutionCallback
BeforeAllCallback
BeforeEachCallback
BeforeTestExecutionCallback
ExecutionCondition
ParameterResolver
TestExecutionExceptionHandler
TestInstancePostProcessor
TestTemplateInvocationContextProvider
几乎所有这些扩展程序都采用某种形式的ExtensionContext
,可以访问test class,test method,test instance,publish report entries的能力,{{ 3}}和其他功能。其中很多都直接在类实例上运行
大多数实现可能会使用store values和reflection using ReflectionSupport
的某种组合,它们都是静态方法,这使得它们很难被模拟。
现在,我已经编写了ExecutionCondition
的实现,或者实现了BeforeEachCallback
和AfterEachCallback
的扩展程序 - 我如何有效地测试它们?
我想我可以模仿ExtensionContext
,但这似乎不是一种有效运用不同代码路径的好方法。
在JUnit的内部,有annotation discovery using AnnotationSupport
,它与ExecutionEventRecorder
一起用于选择和执行测试,然后是JupiterTestEngine
implementation for execution (which is @API(status=INTERNAL)
)。
由于public
上JupiterTestEngine
的可见度,我可以使用相同的模式。
以下是一些具体的例子来说明:
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"));
}
}
仅在一周中提供的某一天运行的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));
}
}
}
设置临时目录的扩展,将其作为参数提供,然后在测试后清除它。这将使用ParameterResolver
,BeforeEachCallback
,AfterEachCallback
和ExtensionContext.Store
。此示例显示扩展实现可能使用多个扩展点,并可以使用存储来跟踪状态。
扩展测试的自定义测试引擎是否是正确的方法?
那么,如何在不依赖内部API且没有"复制"努力进入嘲笑?
答案 0 :(得分:1)
我知道这不是一个完整的答案(但我现在在移动设备上,你的问题非常复杂)...但是试试吧 this project可以帮到你。
如果你稍微限制一下我的问题,我可以尝试更好地帮助你
答案 1 :(得分:0)
自 JUnit 5.4 起,您可以使用Test Kit测试扩展。该功能似乎在 JUnit 5.7 中变得稳定。 (请注意,API在这些版本之间已更改。)
使用测试套件,您可以在实际测试中执行模拟测试,并对结果执行断言。请注意,您可能需要防止您的模拟测试被直接发现。 Issue #1779 of JUnit 5可能会帮助您。