现在,我们已经了解了如何配置JUnit5环境以及如何编写一些测试,让我们来看看封面下的内容。在这篇文章中,我们将讨论JUnit5的架构以及为什么它是这样的。概述本文是本JUnit5系列的一部分:环境搭建基础入门架构系统扩展模型(ExtensionModel)条件断言注入动态测试...(不喜欢看文章的可以点这里看我的演讲,或者看看最近的AvJUGlecture,或者我的PowerPointonDevoxxPL。这个系列的文章是基于Junit5的Milestone2的预发布版本。它可能会改变。如果有新的里程碑版本发布,或者当试用版正式发布后,我会再次更新这篇文章。这里要介绍的大部分知识都可以在JUnit5用户指南中找到(这个链接指向Milestone2的第一版,如果你想看最新版本文档,请点击这里),指南还有更多内容等你发现。下面所有代码都可以在我的Github上找到。目录JUnit4JUnit5*关注点分离*JUnit5重组*架构和System*APILifecycleOpenTestAllianceReviewSummaryShare&FollowJUnit4除Hamcrest外,JUnit4没有外部依赖项,其所有功能都打包在一个工件中。这完全违反了单一职责原则,单一职责原则提供给开发者、IDE、构建工具、其他测试框架、其他扩展等,不同的用户都依赖同一个组件。其中,只有开发人员能够——或者已经能够——以最干净的方式使用它。他们通常只需要JUnit的公共API,别无其他。那太棒了。但是生态系统的其余部分并不像这样使用JUnit:测试框架、扩展,尤其是IDE和构建工具的开发人员,您需要深入了解JUnit的细节,了解其细节:非公共类、内部类API,甚至私有字段。它们的正常工作在很大程度上取决于JUnit的实现细节。这使得JUnit维护团队无法轻易修改框架的这些内部实现,因此团队的开发进度受到很大影响。当然,这些工具的开发者并不是故意的。为了实现我们如此钟爱的特性,他们不得不使用一个内部API,因为JUnit4并没有提供相应的API:一个功能强大到足以满足工具开发者需求的API。JunitLambda团队开始研究JUnit5,希望对此有所了解。JUnit5中的关注点分离退一步说,我们可以很容易地识别出至少有两个不同的关注点需要分离:一个支持测试代码编写的API,以及一个用于识别和运行测试的机制。仔细想想第二点,我们可能会问,“哪些测试?”这当然是指Junit测试。“我知道,不过是哪个版本的测试?”呃……还有,具体是什么类型的测试?好吧,你让我给你……”只有那些旧版本的@Test注解才能运行。还有没有其他新的方式来运行测试?……”好吧好吧,闭嘴!听我说。为了进一步将要识别的测试类型与实际运行它们的两个关注点解耦,上面的第二点需要细分为:支持测试代码的API编写用于识别测试和运行它们的机制*a用于识别和运行特定类型的机制(例如,JUnit5测试机制)*另一套机制来协调上述机制*两者之间API的重组。认识到这两个问题后,“JUnit作为平台”(“JUnit作为工具”(用于编写我们的测试)和“JUnit作为工具”(用于编写我们的测试)概念的分离变得清晰。为了完成这种彻底的分离,JUnit团队决定将JUnit5拆分为三个子项目:JUnitJupiter,它包含我们用来编写测试的API(关注点1),以及一个理解测试代码的引擎(关注点2.1)。Platform提供统一的API用于运行测试,以及一套基于API的工具(重点2.2和2.3)。JUnitVintage提供了一个引擎,用于在JUnit5中运行JUnit3和JUnit4测试(关注点2.1)。架构与体系JUnit5的架构体系就是遵循这种关注点分离思想的产物:junit-jupiter-api(1)开发者用来编写测试的API,包括我们在JUnit基础知识中提到的5以及所有的注释、断言等。junit-platgorm-engine(2.3)包含一组所有测试引擎必须实现的API。这样可以通过统一的接口调用不同的测试引擎。该引擎可以运行普通的JUnit测试,但也可以实现不同的引擎来执行用其他框架编写的测试,例如TestNG、Spock、Cucumber等。junit-jupiter-engine(2.1)junit-platform-engine的一个实现专门用于执行用JUnit5编写的测试的API。junit-vintage-engine(2.1)junit-platform-engineAPI的实现,旨在执行用JUnit3或JUnit4编写的测试。过去,junit-4.12,工件JUnit4的一部分,有两个作用:它是开发人员实现测试的API,它包含执行测试的核心组件。这个引擎可以被认为是低版本JUnit3/4和JUnit5之间的适配器。junit-platform-launcher(2.2)部分使用服务加载器ServiceLoader来发现测试引擎并协调不同实现之间的执行。它为IDE和构建工具提供API,使它们能够与测试执行过程进行交互,例如运行单个测试、收集测试结果并显示它们等。听起来很酷,对吧?这部分架构对我们生态链前端的用户来说基本是透明的。我们的项目只需要引入API依赖来编写测试,让工具来处理其余的组件。API生命周期下面我们来谈谈大家使用的内部API。JUnit5团队希望这个问题也能得到解决,为此为JUnit的API建立了生命周期。在这里,我截取了这里源码中给出的部分解释。内部API(internal)不允许除JUnit开发人员以外的任何人使用。API的这一部分可能会被删除,恕不另行通知。不应再使用并可能在下一个次要版本中删除的已弃用API。用于新的实验性功能的实验性API,这些API可能是或已经公开可用并正在接收反馈。可以使用,但要谨慎。这些API将来可能会升级为In-Maintenance或Stable,但也可能会被删除,恕不另行通知。维护使用API的功能,以便在发布主要版本的下一个次要版本时至少不会发生向后不兼容的更改。如果未来有计划在维护中移除某个API,则会先将其推回deprecated阶段。稳定版(Stable)使用API??的特性,至少在下一个大版本发布之前,不会出现向后不兼容的变化。JUnit公开的类使用@API(usage)注释,其中usage是上述值之一。团队希望这能够让API调用者充分了解他们所使用的API处于什么样的生命周期,同时也希望能够让每个团队自由决定是否更改或移除过时的API。开放测试联盟其实还有一件事。Junit5的架构使IDE和构建工具能够将其用作中间层来运行所有类型的测试框架(前提是该框架实现了其相应的引擎)。这样工具本身就不需要实现框架相关的测试支持,只需要使用一套统一的借口就可以实现测试发现、测试执行和结果收集。真的可能吗?失败的测试通常用异常来描述。但是不同的测试框架和断言库之间没有统一的接口。相反,它们通常实现自己的不同版本(通常继承AssertionError或RuntimeException)。这使得不同框架之间的互操作变得更加复杂,也使得工具之间无法简单地使用一套统一的接口。为了解决这个问题,JunitLambda团队创建了一个独立的项目,TheOpenTestAlliancefortheJVM。以下是他们的提议:根据JUnitLambda团队与IDE以及来自Eclipse、Gradle和Intellij的构建工具开发人员之间最近的讨论,我们呼吁一个开源项目来提供一个基于JVM的测试库一组最小的公共接口到测试框架。该项目的主要目标是为各种测试框架(如JUnit、TestNG、Spock等)和三方断言库(Hamcrest、Assert等)提供一个通用的异常集合。有了这个集合,IDE和构建工具可以为所有测试过程提供统一的接口——例如失败断言的处理、失败的假设确定、测试执行过程的可视化、IDE中测试结果报告的生成等.-处理。到目前为止,该项目的呼吁似乎很少或根本没有引起注意。如果您认为这是个好主意,您可以支持它,例如,向您经常使用的测试框架维护者表达您的意见。回顾与总结在这篇文章中,我们介绍了JUnit5的架构设计,将原来的API分为两部分:编写测试部分的API和执行测试的引擎。引擎又分为三部分:解析测试代码的API,测试执行器(启动器),以及一些支持不同测试框架的引擎实现。这样,开发者只需要为项目引入API部分的依赖(编写测试用),而测试框架的开发者只需要实现引擎部分的API即可(其他工作已经交由JUnit处理),而构建工具只需要实??现launcherAPI来协调测试执行。
