网站策划论文,wordpress没有关键字,dw做网站简单首页,阿里云网站怎么备案junit5和junit4最近#xff0c;我们了解了JUnit的新扩展模型以及它如何使我们能够将自定义行为注入测试引擎。 我向你保证要看情况。 现在就开始吧#xff01; 条件允许我们在应该执行或不应该执行测试时定义灵活的标准。 它们的正式名称是“ 条件测试执行” 。 总览 本系列… junit5和junit4 最近我们了解了JUnit的新扩展模型以及它如何使我们能够将自定义行为注入测试引擎。 我向你保证要看情况。 现在就开始吧 条件允许我们在应该执行或不应该执行测试时定义灵活的标准。 它们的正式名称是“ 条件测试执行” 。 总览 本系列中有关JUnit 5的其他文章 建立 基本 建筑 扩展模型 条件 注射 … 在新兴的《 JUnit 5用户指南》中可以找到您将在此处阅读的更多内容以及更多内容。 请注意它基于Alpha版本因此可能会发生变化。 确实我们鼓励我们提出问题或提出请求以便JUnit 5可以进一步改进。 请利用这个机会 这是我们帮助JUnit帮助我们的机会因此如果您能在这里看到一些改善请确保将其上游 。 如有必要此帖子将得到更新。 我在这里显示的代码示例可以在GitHub上找到 。 条件扩展点 还记得我们所说的扩展点吗 没有 简而言之它们很多每个都与特定的接口有关。 可以将这些接口的实现传递给JUnit带有ExtendWith批注它将在适当的时候调用它们。 对于条件需要关注两个扩展点ContainerExecutionCondition和TestExecutionCondition。 public interface ContainerExecutionCondition extends Extension {/*** Evaluate this condition for the supplied ContainerExtensionContext.** An enabled result indicates that the container should be executed;* whereas, a disabled result indicates that the container should not* be executed.** param context the current ContainerExtensionContext*/ConditionEvaluationResult evaluate(ContainerExtensionContext context);}public interface TestExecutionCondition extends Extension {/*** Evaluate this condition for the supplied TestExtensionContext.** An enabled result indicates that the test should be executed;* whereas, a disabled result indicates that the test should not* be executed.** param context the current TestExtensionContext*/ConditionEvaluationResult evaluate(TestExtensionContext context);} ContainerExecutionCondition确定是否执行容器中的测试。 在带有注释测试方法的通常情况下测试类将是容器。 在同一场景中各个测试方法的执行由TestExecutionConditions确定。 我说“在通常情况下”是因为不同的测试引擎对容器和测试的解释可能非常不同。类和方法只是最常见的解释。 这已经差不多了。 任何条件都应实现这些接口中的一个或两个并在其评估实现中进行所需的检查。 已停用 最简单的条件是甚至没有评估的条件如果存在我们手工制作的注释我们总是总是禁用测试。 因此让我们创建Disabled Target({ ElementType.TYPE, ElementType.METHOD })
Retention(RetentionPolicy.RUNTIME)
ExtendWith(DisabledCondition.class)
public interface Disabled { } 和匹配的扩展名 public class DisabledConditionimplements ContainerExecutionCondition, TestExecutionCondition {private static final ConditionEvaluationResult ENABLED ConditionEvaluationResult.enabled(Disabled is not present);Overridepublic ConditionEvaluationResult evaluate(ContainerExtensionContext context) {return evaluateIfAnnotated(context.getElement());}Overridepublic ConditionEvaluationResult evaluate(TestExtensionContext context) {return evaluateIfAnnotated(context.getElement());}private ConditionEvaluationResult evaluateIfAnnotated(AnnotatedElement element) {OptionalDisabled disabled AnnotationUtils.findAnnotation(element, Disabled.class);if (disabled.isPresent())return ConditionEvaluationResult.disabled(element is Disabled);return ENABLED;}} 像馅饼一样容易对吧 也是正确的因为它与真正的Disabled实现几乎相同。 只有两个小区别 官方注释不需要随身携带扩展名因为它是默认注册的。 可以给出一个原因当跳过禁用的测试时会记录该原因。 小警告当然您有什么想法AnnotationUtils是内部API但其功能可能很快就会正式可用 。 现在让我们尝试一些不那么琐碎的事情。 DisabledOnOs 如果我们使用的是正确的操作系统也许我们只想运行一些测试。 简单的解决方案 同样我们从注释开始 Target({ ElementType.TYPE, ElementType.METHOD })
Retention(RetentionPolicy.RUNTIME)
ExtendWith(OsCondition.class)
public interface DisabledOnOs {OS[] value() default {};} 这次需要一个值如果不是则取一堆即不应运行测试的操作系统。 OS只是一个枚举每个操作系统都有一个值。 而且它有一个方便的静态OS define方法您猜对了它确定了代码在其上运行的操作系统。 这样让我们转向OsCondition。 它必须检查注释是否存在但还要检查当前的操作系统是否是提供给注释的操作系统之一。 public class OsCondition implements ContainerExecutionCondition, TestExecutionCondition {// both evaluate methods forward to evaluateIfAnnotated as aboveprivate ConditionEvaluationResult evaluateIfAnnotated(AnnotatedElement element) {OptionalDisabledOnOs disabled AnnotationUtils.findAnnotation(element, DisabledOnOs.class);if (disabled.isPresent())return disabledIfOn(disabled.get().value());return ENABLED;}private ConditionEvaluationResult disabledIfOn(OS[] disabledOnOs) {OS os OS.determine();if (Arrays.asList(disabledOnOs).contains(os))return ConditionEvaluationResult.disabled(Test is disabled on os .);elsereturn ConditionEvaluationResult.enabled(Test is not disabled on os .);}} 我们可以如下使用它 Test
DisabledOnOs(OS.WINDOWS)
void doesNotRunOnWindows() {assertTrue(false);
} 真好 少礼 但是我们可以做得更好 借助JUnit的可自定义注释我们可以使此条件更加平滑 TestExceptOnOs(OS.WINDOWS)
void doesNotRunOnWindowsEither() {assertTrue(false);
} 要实现TestExceptOnOs只需执行以下操作就可以了 Retention(RetentionPolicy.RUNTIME)
Test
DisabledOnOs(/* somehow get the value below */)
public interface TestExceptOnOs {OS[] value() default {};} 当执行测试并扫描OsCondition :: evaluateIfAnnotated中的DisabledOnOs时我们会发现它在TestExceptOnOs上进行了元注释并且我们的逻辑将正常工作。 但是我找不到一种方法使DisabledOnOs可以访问提供给TestExceptOnOs的OS值。 你能 下一个最佳选择是对新注释简单地使用相同的扩展名 Retention(RetentionPolicy.RUNTIME)
ExtendWith(OsCondition.class)
Test
public interface TestExceptOnOs {OS[] value() default {};} 然后我们拉皮条OsCondition :: evaluateIfAnnotated包括新的案例… private ConditionEvaluationResult evaluateIfAnnotated(AnnotatedElement element) {OptionalDisabledOnOs disabled AnnotationUtils.findAnnotation(element, DisabledOnOs.class);if (disabled.isPresent())return disabledIfOn(disabled.get().value());OptionalTestExceptOnOs testExcept AnnotationUtils.findAnnotation(element, TestExceptOnOs.class);if (testExcept.isPresent())return disabledIfOn(testExcept.get().value());return ConditionEvaluationResult.enabled();
} ……我们完成了。 现在我们确实可以按照我们希望的方式使用它。 抛光 创建倒置的注释如果不在指定的操作系统之一上禁用则完全相同但是有了它们改进的名称和静态导入我们可以在这里结束 TestOn(WINDOWS)
void doesNotRunOnWindowsEither() {assertTrue(false);
} 还不错吧 在CC-BY 2.0下由CWCS托管主机发布 DisabledIfTestFails 让我们再尝试一件事–这次我们将使其变得非常有趣 假设有很多集成测试并且如果其中一个测试由于特定的异常而失败那么其他测试也必然会失败。 因此为了节省时间我们想禁用它们。 那么我们在这里需要什么呢 显而易见我们必须以某种方式收集在测试执行过程中引发的异常。 这必须与测试类的生存期绑定因此我们不会禁用测试因为某些异常会在完全不同的测试类中发生。 然后我们需要一个条件实现该条件实现检查是否抛出了特定异常如果存在则禁用测试。 收集例外 查看扩展点列表我们发现“异常处理”。 相应的接口看起来很有希望 /*** ExceptionHandlerExtensionPoint defines the API for Extension Extensions* that wish to react to thrown exceptions in tests.** [...]*/
public interface ExceptionHandlerExtensionPoint extends ExtensionPoint {/*** React to a throwable which has been thrown by a test method.** Implementors have to decide if they* * - Rethrow the incoming throwable* - Throw a newly constructed Exception or Throwable* - Swallow the incoming throwable** [...]*/void handleException(TestExtensionContext context, Throwable throwable)throws Throwable;
} 因此我们将实现handleException来存储然后重新抛出异常。 您可能还记得我写的有关扩展和状态的内容 引擎在实例化扩展时以及将实例保留多长时间时不做任何保证因此它们必须是无状态的。 他们需要维护的任何状态都必须写入JUnit并从中加载。 好的所以我们使用商店。 有效地收集了我们想要记住的东西。 我们可以通过传递给大多数扩展方法的扩展上下文来访问它。 稍作修改后发现每个上下文都有其自己的存储因此我们必须决定访问哪个上下文。 每个测试方法TestExtensionContext和整个测试类ContainerExtensionContext都有一个上下文。 请记住我们想将在执行所有测试期间抛出的所有异常存储在一个类中但不能存储更多即不存储其他测试类抛出的异常。 事实证明ContainerExtensionContext及其存储正是我们需要的。 因此这里我们获取容器上下文并使用它来存储一组引发的异常 private static final Namespace NAMESPACE Namespace.of(org, codefx, CollectExceptions);
private static final String THROWN_EXCEPTIONS_KEY THROWN_EXCEPTIONS_KEY;SuppressWarnings(unchecked)
private static SetException getThrown(ExtensionContext context) {ExtensionContext containerContext getAncestorContainerContext(context).orElseThrow(IllegalStateException::new);return (SetException) containerContext.getStore(NAMESPACE).getOrComputeIfAbsent(THROWN_EXCEPTIONS_KEY,ignoredKey - new HashSet());
}private static OptionalExtensionContext getAncestorContainerContext(ExtensionContext context) {OptionalExtensionContext containerContext Optional.of(context);while (containerContext.isPresent() !(containerContext.get() instanceof ContainerExtensionContext))containerContext containerContext.get().getParent();return containerContext;
} 现在添加一个异常很简单 Override
public void handleException(TestExtensionContext context, Throwable throwable)throws Throwable {if (throwable instanceof Exception)getThrown(context).add((Exception) throwable);throw throwable;
} 实际上这本身就是一个有趣的扩展。 也许它也可以用于分析。 无论如何我们将要查看抛出的异常因此我们需要一个公共方法 public static StreamException getThrownExceptions(ExtensionContext context) {return getThrown(context).stream();
} 有了这个扩展任何其他扩展都可以检查到目前为止已经抛出了哪些异常。 禁用 其余部分与以前非常相似因此让我们快速了解一下 Target(ElementType.METHOD)
Retention(RetentionPolicy.RUNTIME)
ExtendWith(DisabledIfTestFailedCondition.class)
public interface DisabledIfTestFailedWith {Class? extends Exception[] value() default {};} 请注意我们仅在方法上允许使用此注释。 在测试类上使用它可能很有意义但现在让我们保持简单。 因此我们仅实现TestExecutionCondition。 在检查了是否存在我们的注释之后我们使用用户提供的异常类调用disableIfExceptionWasThrown private ConditionEvaluationResult disableIfExceptionWasThrown(TestExtensionContext context,Class? extends Exception[] exceptions) {return Arrays.stream(exceptions).filter(ex - wasThrown(context, ex)).findAny().map(thrown - ConditionEvaluationResult.disabled(thrown.getSimpleName() was thrown.)).orElseGet(() - ConditionEvaluationResult.enabled());
}private static boolean wasThrown(TestExtensionContext context, Class? extends Exception exception) {return CollectExceptionExtension.getThrownExceptions(context).map(Object::getClass).anyMatch(exception::isAssignableFrom);
} 把它放在一起 如果在之前抛出特定类型的异常这就是我们使用这些批注禁用测试的方式 CollectExceptions
class DisabledIfFailsTest {private static boolean failedFirst false;Testvoid throwException() {System.out.println(I failed!);failedFirst true;throw new RuntimeException();}TestDisabledIfTestFailedWith(RuntimeException.class)void disableIfOtherFailedFirst() {System.out.println(Nobody failed yet! (Right?));assertFalse(failedFirst);}}摘要 哇那是很多代码 但是到目前为止我们真的知道如何在JUnit 5中实现条件 创建所需的注释和ExtendWith条件实现 实现ContainerExecutionConditionTestExecutionCondition或同时实现 检查是否存在新的注释 进行实际检查并返回结果 我们还看到这可以与其他扩展点结合使用如何使用商店来保留信息并且自定义注释可以使扩展使用起来更加优雅。 有关标记扩展点的更多乐趣请在讨论参数注入时查看本系列的下一篇文章。 翻译自: https://www.javacodegeeks.com/2016/05/junit-5-conditions.htmljunit5和junit4