「译」JUnit 5 系列:架构体系

原文地址:http://blog.codefx.org/design/architecture/junit-5-architecture/
原文日期:29, Mar, 2016
译文首发:Linesh 的博客:JUnit 5 系列:架构体系
个人 Github:http://github.com/linesh-simplicityhtml

如今,咱们已经知道了 如何配置 JUnit 5 环境如何写一些测试,接下来就来看一点封面下的内容吧。本篇咱们将讨论 JUnit 5 的架构体系,以及它之成形如此的缘由。前端

概述

本文章是这个 JUnit 5 系列的一部分:java

(若是不喜欢看文章,你能够戳这里看个人演讲,或者看一下最近的 vJUG 讲座,或者我在 DevoxxPL 上的 PPTgit

本系列文章都基于 Junit 5发布的先行版 Milestone 2。它可能会有变化。若是有新的里程碑(milestone)版本发布,或者试用版正式发行时,我会再来更新这篇文章。github

这里要介绍的多数知识你均可以在 JUnit 5 用户指南 中找到(这个连接指向的是先行版 Milestone 2,想看的最新版本文档的话请戳这里),而且指南还有更多的内容等待你发掘。下面的全部代码均可以在 个人 Github 上找到。api

目录

  • JUnit 4
  • JUnit 5
    • 分离的关注点
    • JUnit 5 的从新组织
    • 架构及体系
    • API 生命周期
  • Open test alliance
  • 回顾总结
  • 分享&关注

JUnit 4

除了 Hamcrest,JUnit 4没有任何外部依赖,其全部的功能都被打包在一个构件(artifact)中。这彻底违反了单一职责原则,它被提供给开发者、IDE、构建工具、其余测试框架、其余扩展等使用,不一样的使用者,依赖的都是一个一样的构件。架构

而在这其中,只有开发者能——或者说曾经能——以最干净的方法来使用它。他们一般只须要 JUnit 的公共 API,不须要管其余的。很是好。框架

但生态圈中的其余成分则不是这样使用 JUnit:测试框架、扩展,特别是 IDE 和构建工具的开发者,他们须要深刻到 JUnit 的深处,到它的细枝末节:非 public 的类、内部 API,甚至 private 字段。它们的正常工做极大地依赖于 JUnit 的实现细节。这使得 JUnit 维护团队不能轻易地修改框架的这些内部实现,所以团队的开发进度受到了很大的影响。ide

固然,这些工具的开发者们也并不是有意为之。为了实现那些咱们十分喜好的特性,他们不得不使用内部的 API,由于 JUnit 4 并无提供相应的 API:一个强大到足以知足工具开发者们需求的 API。工具

Junit Lambda 团队开始着手于 JUnit 5 的开发,但愿能让这一切变得明朗起来。

JUnit 5

分离的关注点

退一步想,咱们不难辨识出,这里至少有两个不一样的关注点须要分离:

  1. 一个支持测试代码撰写的 API
  2. 一个识别测试、运行测试的机制

再仔细思考一下第二点,咱们可能会问,“哪些测试?”这个固然是指 Junit 测试。“我知道,但具体是哪些版本的测试呢?”呃…“还有,具体是指什么类型的测试?”好吧,你让我给你……“只能跑那些老版本的 @Test 注解的测试么?有没有其余新的方法来运行测试呢?……”行行行,都给我闭嘴!听我讲着。

为了进一步将待识别测试的类型 与 实际运行它们 这两个关注点解耦,上面的第二点须要细分:

  1. 一个支持测试代码撰写的 API
  2. 一个识别测试、运行测试的机制
    1. 一个识别、运行特定类型(好比,JUnit 5测试的机制)
    2. 另外一套协调上述机制的机制
    3. 上二者之间的 API

JUnit 5 的从新的组织

识别出这两个关注点之后,“做为平台的 JUnit ”(用于运行咱们的测试)和“做为工具的 JUnit ”(用于撰写咱们的测试)这两个概念的分离就清晰了。为了完成这个完全的分离,JUnit 团队决定将 JUnit 5 分红三个子项目:

JUnit Jupiter
包含了咱们用于撰写测试的 API(关注点1),以及一个能理解测试代码的引擎(关注点2.1)。

JUnit Platform
提供了一套统一的 API 以运行测试,及基于 API 之上的一套工具(关注点2.2和2.3)。

JUnit Vintage
提供了一套引擎,用以在 JUnit 5 中运行 JUnit 3 和 JUnit 4 的测试(关注点2.1)。

架构与体系

JUnit 5 的架构体系彻底是遵循这个关注点分离思想的产物:

junit-jupiter-api(1)
开发者用于撰写测试的 API,包含了咱们在JUnit 5 的基础知识一节中所说起的全部注解、断言等。

junit-platgorm-engine(2.3)
包含了一套全部测试引擎都必须实现的 API。这样,不一样的测试引擎之间能够经过统一的接口被调用。引擎能够跑正常的 JUnit 测试,但也能够实现不一样的引擎用以执行其余框架写成的测试,如 TestNGSpockCucumber 等。

junit-jupiter-engine(2.1)
junit-platform-engine API 的一个实现,专门用于执行 JUnit 5 撰写的测试。

junit-vintage-engine(2.1)
junit-platform-engine API 的一个实现,专门用于执行 JUnit 3 或 JUnit 4 撰写的测试。过去,JUnit 4 的构件 junit-4.12 充当了两个角色:它既是开发人员用于实现测试的 API,又包含了用以执行测试的核心组件。这个引擎,能够认为是低版本的 JUnit 3/4 与 JUnit 5 之间的一个适配器。

junit-platform-launcher(2.2)
这部分使用了一个服务加载器 ServiceLoader 来发现测试引擎,并协调不一样实现之间的执行。它提供了一个 API 给 IDE 和构建工具,使得它们可以与测试执行过程交互,好比,运行单个的测试、搜集测试结果并展现等。

听起来怎样,很酷吧。

这部分架构对于咱们生态链前端的使用者来讲基本是透明的。咱们的项目只须要引入一个用于编写测试的 API 依赖,其他的组件让工具去操心便可。

API 生命周期

如今来讲说那些你们都在使用的内部 API。JUnit 5 团队但愿这个问题也能获得解决,为此给 JUnit 的 API 设立了生命周期。这里,我将源码中给出的部分解释截取于此。

内部 API(internal)
不容许被 JUnit 开发者以外的任何人使用。这部分 API 可能被移除,而且不会事先通知。

已过期(Deprecated)
不该该再被使用的 API,它们可能在下次小版本发布时被移除。

实验阶段(Experimental)
为一些新的、实验阶段的特性所使用的 API,这些新特性可能会或已经被公开使用并接受反馈中。
可使用,但要谨慎。这些 API 将来可能被提高至 维护中稳定 级别,但也可能不带提早通知就被移除。

维护中(Maintained)
使用该 API 的特性,至少在该大版本的下一个小版本发布时不会发生向后不兼容的改变。若是将来有移除维护中 API 的计划,它会先被打回到 已过期 阶段。

稳定(Stable)
使用该 API 的特性,至少在下个大版本发布以前不会发生向后不兼容的改变。

JUnit 对外公开的类都带有一个 @API(usage) 注解,其中 usage 是上面几个值中的其中一个。团队但愿这能给 API 的调用方以充足的信息,即他们所使用的 API 处于什么生命周期中,同时,也但愿给每一个团队以自由,让他们决定是否改变或移除过期 API 。

Open Test Alliance

其实还有一件事。Junit 5 的体系结构使得 IDE 和构建工具可以将其做为中间层,以运行全部类型的测试框架(前提是该框架实现了其对应的引擎)。这样的话,工具自己就不须要去实现框架相关的测试支持,它们只须要使用一套统一的借口,便可实现测试发现、测试执行和结果收集。

是嘛,真的能够吗?

失败的测试,一般使用异常来描述。但不一样的测试框架和断言库之间并没有一个统一的接口。相反,它们一般实现了各自不一样的版本(常见的是继承 AssertionErrorRuntimeException )。这就使得不一样框架间的互操做变得更加复杂,也使得工具之间没法简单使用一套统一的接口。

为了解决这个问题,Junit Lambda 团队又分出来一个独立的项目,The Open Test Alliance for the JVM。这是它们的提议:

基于 JUnit Lambda 团队近来与来自Eclipse、Gradle 及 Intellij 等 IDE 和构建工具开发者所展开的讨论,咱们呼吁要创建这样一个开源项目:它用于提供一套基于 JVM的 测试库与测试框架 间的最小公共接口集。

项目主要目标是,为各测试框架(如 JUnit、TestNG、Spock 等)和三方断言库(Hamcrest、Assert 等)提供一个公共的异常集合。有了这个集合,IDE 和构建工具就能够一个统一的接口对全部测试过程——如对失败断言、失败假言断定的处理、对测试执行过程的可视化、在 IDE 中生成测试结果报告等——进行处理。

截止目前,该项目的呼吁彷佛并未引发太多重视,或说是基本未获得重视。若是你以为这是个好的想法,你能够经过一些方式来支持,好比向你常用的测试框架维护者发出声音。

回顾总结

本篇咱们介绍了 JUnit 5 的架构设计,它将原有的 API 分红了两部分:编写测试部分的 API 和 执行测试的引擎。这个引擎进一步地被切分红三个部分:一个解析测试代码的 API、一个测试执行器(launcher),和一些支持不一样测试框架的引擎实现。这样开发者只须要为项目引入 API 部分的依赖(用于编写测试),而测试框架的开发者们则只须要实现引擎部分的 API(其余工做已经由 JUnit 处理了),构建工具方面也只须要实现 launcher API以协调测试执行。

下篇文章将会介绍 JUnit 5 的可拓展性。敬请期待。

相关文章
相关标签/搜索