如何在 JUnit 5 中模拟真实性 BeforeAll 和 AfterAll-java教程

首页 2024-07-10 01:55:34

介绍

junit 5 开发人员是众所周知的 java 测试框架/库。是的 junit 4 它的演变有许多伟大的功能。最重要的是设置前后条件,通过术语“前”(前条件)和“后”(后条件)来理解。

它有 2 各种支持方式:Before/After All 和 Before/After Each。
“全部”部分意味着代码块可以在初始化所有测试之前或之后作为前后条件执行。 “Each“部分意味着代码块可以作为每次测试前后的前后条件。

JUnit 5 官方文件对这些策略说了以下内容,即注释:

注释 描述 @BeforeEach 表示注释的方法应该在当前类别中 @Test、@RepeatedTest、@ParameterizedTest 或 @TestFactory 方法以前执行;类似; JUnit 4 的 @Before。除非它们被重写,否则这些方法是继承的 @AfterEach 表示注释的方法应在当前类中的每个类中 @Test、@RepeatedTest、@ParameterizedTest 或 @TestFactory 方法后执行;类似; JUnit 4 的 @After。除非它们被重写,否则这种方法将被继承。 @BeforeAll 表示注释的方法应该在当前类别中的所有方法@Test、@RepeatedTest、@ParameterizedTest、@以前执行TestFactory方法;类似于 JUnit 4 的 @BeforeClass。这种方法是继承的,除非它们被重写,必须是静态的,除非使用“每一类”来测试生命周期。 @毕竟 表示注释的方法应该执行。毕竟,在当前类别中@Test、@RepeatedTest、@ParameterizedTest、@类似于TestFactory方法; JUnit 4 的 @AfterClass。这种方法是继承的,除非它们被重写,必须是静态的,除非使用“每一类”来测试生命周期。 我们需要解决哪些问题?
通过查看注释,我们知道它涵盖了我们测试所需的大部分场景。 我们有 @BeforeAll 和 @AfterAll 注释是一般的前后条件。

一种常见的测试模式应用于良好的测试架构 BaseTest 类:我们可以添加前后条件,这些前后条件将在不同的测试之间继承和共享。通常,我们希望以不同的方式控制这些条件。开发人员有不同的方式 BaseTest 控制模式:

在任何测试开始时只打开浏览器一次,以节省时间

    保持打开不同测试类别的容器(Testcontainer)
  • 在执行任何测试前摄取数据,并在执行所有测试后删除数据
  • 我有坏消息:JUnit 5 由于上述三个场景无法控制,因此无法控制上述三个场景 @BeforeAll 和 @AfterAll 它是为每个测试实例(即每个测试类别)执行的。其他框架(如 TestNG)具有称为 @BeforeSuite 和 @AfterSuite 这就是我们想要的功能 JUnit 5 不支持的功能。
让我们知道如何使用它 JUnit 5 实现这一目标以及如何解决这一问题。

BeforeAllCallback 和 AfterAllCallback 接口

你可能会像我一样搜索一些谷歌,遇到beforeallcalback和afteralcalcalback接口,它们是测试生命周期回调的扩展。这似乎是一个很好的解决方案,因为这些接口允许你运行 @BeforeAll 或 @AfterAll。

公共类 MyExtension 实现 BeforeAllCallback、AfterAllCallback { @覆盖 公共无效 afterAll(ExtensionContext 上下文){ // 预一般条件 } @覆盖 公共无效beforeall(Extensioncontext上下文){ //发布一般条件 } }

UML 使用名称显示在图中 MyExtension 的 JUnit 5 扩展的 BaseTest,实现了这种扩展 BeforeAllCallback 和 AfterAllCallback。FeatureTest1基础测试 和Featuretest2。请注意,MyExtension 有 beforeAll 和 afterAllMethods,BaseTest 也有。

这是因为它解决了这个问题, MyExtension 它将在整体情况之前和之后扮演角色,因为 BaseTest 在每个测试实例中,中间的扩展将运行,这意味着 Feature1Test 和 Feature2Test 运行时运行。不幸的是,事实并非如此。如果我们只在每种方法中添加它 System.out.println() 调用时,输出如下:

[信息] ---------------------------------------------------------- --------- [信息] 测试 [信息] ---------------------------------------------------------- -------- [信息] 运行 com.eliasnogueira.feature1.Feature1Test MyExtension.beforeAll BaseTest.beforeAll 功能1测试.test1 功能1测试.测试2 功能1测试.测试3 毕竟,基础测试 毕竟,我的扩展 [信息] 测试操作:3,失败:0,错误:0,跳过:0,已用时间:0.018 秒 -- 在 com.eliasnogueira.feature1.Feature1Test 中 [信息] 运行 com.eliasnogueira.feature2.Feature2Test MyExtension.beforeAll BaseTest.beforeAll 功能2测试.test1 功能1测试.测试2 毕竟,基础测试 毕竟,我的扩展 [信息] 测试操作:2,失败:0,错误:0,跳过:0,时间:0.002 秒 -- 在 com.eliasnogueira.feature2.Feature2Test 中

您可以看到 MyExtension 中间的方法针对每个测试类别和 BaseTest 操作。这意味着 JUnit 运行它作为每个测试实例。不幸的是,JUnit 5 对于整个测试执行的任何一般前提条件,都没有解决方案。

想看看它的实际效果吗?

– 克隆这个仓库:git clone https://github.com/eliasnogueira/junit5-before-after-all
– 切换到无解分支 – 运行 mvn 测试 如何解决
隧道尽头光明,并不难。和其他人一样,我在谷歌里,在这里 Stackoverflow 在线程上发现了一个有趣的解决方案:https://stackoverflow.com/questions/43282798/in-junit-5-how-to-run-code-before-all-test.

请注意,这是未来可能的解决方案 JUnit 这个版本不起作用。

基于使用的解决方案 BeforeAllCallback 在并行测试运行过程中,接口使用线程锁来解决一般的前置条件 ExtensionContext.Store.CloseableResource 模拟接口的后置条件 JUnit 存储机制。别担心,我会分解的。

这个例子

这是一种简单的方法,只是为了向你展示这种方法的有效性。这个例子显示了一般性 BaseTest 以及每个功能 BaseTest,它将创造一种能力来扩展,以提供一般的前后条件。 扩展实施

实现可分四步完成,最终解决方案如下:

1 公共类Setupextension 实现Beforealcalback, Store.CloseableResource { 2 3 private static final Lock LOCK = new ReentrantLock(); 4 私有静态易失性布尔开始= false; 5 6 @覆盖 7 公共无效beforeall(Extensioncontext上下文){ 8 锁.lock(); 9 10 尝试{ 11 if (!开始) { 12开始=真; 13 System.out.println([前置条件]应只运行一次”); 14 context.getRoot().getStore(Namespace.GLOBAL).put(“后置条件占位符”, this); 15} 16}最后{ 17 // 释放访问权限 18 锁.unlock(); 19} 20} 21 22 23 @覆盖 24 ()公共无效关闭(){ 25 System.out.println([后置条件]应只运行一次”); 26} 27}

实现必要的接口

第 1 行显示两个接口:BeforeAllCallback 重写 beforeAll() 该方法将控制一般的前提条件,ExtensionContext.Store.CloseableResource 重写 close() 该方法将模仿一般的后置条件。

单次执行控制beforeall

要确保只执行一次,必须应用一种策略:控制它已经开始,这样beforeall()就不会再执行了。

第 8 行显示我们正在锁定线程。确保任何并行执行都是必要的。第一 11 检查代码以前是否执行过。当布尔值启动首次设置为 true 确保它不会在后续操作中转移到代码块。最后一部分解锁了线程。

一般前提条件的实施

任何必要的实现一般前提条件都应该放在 if 内部条件,就这么简单。我们可以在第一位。 13 看到这一点。

模仿一般的后置条件,添加信号(存储)

这里模仿一般后置条件的方法是通过 Store。在 JUnit 5 在扩展过程中,我们可以存储对象,以便将来进行搜索,这是可以使用的 getStore(context).put(key, value) 上下文为根或当前上下文,键、值为键,增加其存储值。

第 14 为以后自动创建虚拟存储对象 close() 在调用方法时使用。

实现一般的后置条件

ExtensionContext.Store.CloseableResource 接口中的 close() 该方法将在扩展生命周期结束时被调用 [参考]。这是程序退出前执行任何代码的最后机会。这样,我们就可以模拟一般的后置条件。

代码示例

https://github.com/eliasnogueira/junit5-before-after-all 该项目显示了基于本文解释的实现,与“示例”部分的图表相匹配。 在运行测试过程中,您将看到以下输出:

[信息] ---------------------------------------------------------- --------- [信息] 测试 [信息] ---------------------------------------------------------- -------- [信息] 运行 com.eliasnogueira.feature1.Feature1Test [前提条件] 应该只运行一次 BaseTest.beforeAll BasefeatureTest.beforeAll 功能1测试.test1 功能1测试.测试2 功能1测试.测试3 BasefeatureTest.毕竟 毕竟,基础测试 [信息] 测试操作:3,失败:0,错误:0,跳过:0,已用时间:0.019 秒 -- 在 com.eliasnogueira.feature1.Feature1Test 中 [信息] 运行 com.eliasnogueira.feature2.Feature2Test BaseTest.beforeAll Basefeature2Test.beforeAll 功能2测试.test1 功能1测试.测试2 Basefeature2Test.毕竟 毕竟,基础测试 [信息] 试验操作:2,失败:0,错误:0,跳过:0,时间:0.002 秒 -- 在 com.eliasnogueira.feature2.Feature2Test 中 [后置条件] 它应该只运行一次

请注意,一般的前提条件是作为 [pre-condition] Should run only Once 作为文本输出的一般后置条件 [post-condition] Should run only Once 输出。您可以在所有测试执行的开始和结束时分别看到它们。

使用这种简单的方法,您可以在代码中具备一般的前后条件。

测试愉快!


以上就是如何在这里 JUnit 5 中模拟是真实的 BeforeAll 和 更多关于AfterAll的细节,请关注其他相关文章!


p