【问题标题】:With JUnit 5, how to share information in `ExtensionContext.Store` between test instances?使用 JUnit 5,如何在测试实例之间共享 `ExtensionContext.Store` 中的信息?
【发布时间】:2018-03-28 11:06:11
【问题描述】:

我在使用 JUnit 5(5.0 或 5.1)和自定义扩展时遇到了麻烦。

我们正在使用服务加载器来加载所有实现,然后修改我们的扩展的引导方式。这些实现只能加载一次,所以我正在考虑使用ExtensionContext.Store 并将其放置在那里。然后,每个后续测试实例都将仅从 Store 加载它,而不是通过服务加载器。

现在,我什至知道分层上下文结构,并且我知道您可以通过ExtensionContext.getRoot() 获得一些“根”上下文。但是这个“根”上下文(JupiterEngineExtensionContext 的实例)并不是真正的根 - 每个测试实例都有不同的上下文。

假设您有FooTestBarTest,然后为它们中的每一个打印出getRoot()

org.junit.jupiter.engine.descriptor.JupiterEngineExtensionContext@1f9e9475 org.junit.jupiter.engine.descriptor.JupiterEngineExtensionContext@6c3708b3

因此尝试从 Store 检索以前存储的信息失败。

  • 是否有意设置此限制?它使ClassExtensionContextJupiterEngineExtensionContext 之间的界限变得非常模糊。
  • 还有其他方法可以通过扩展全局存储一些信息吗?

这是我尝试与商店合作的(非常)简化的版本(基本上删除了所有其他信息)。我还添加了一些System.out.print() 电话来强调我所看到的。在两个测试类上执行这个扩展会得到我上面描述的结果:

    public class MyExtension implements BeforeAllCallback {

    @Override
    public void beforeAll(ExtensionContext context) throws Exception {
        System.out.println(context.getRoot());
        if (context.getRoot().getStore(Namespace.create(MyExtension.class)).get("someIdentifier", String.class) == null) {
            context.getRoot().getStore(Namespace.create(MyExtension.class)).put("someIdentifier", "SomeFooString");
        } else {
            // this is never executed
            System.out.println("Found it, no need to store anything again!");
        }
    }
}

编辑:这是 GH(link) 上的一个最小项目,由 mvn clean install 运行,它显示了我看到的行为。

【问题讨论】:

  • getRoot() 实际上不应该返回不同的实例。您如何运行测试?
  • @MarcPhilipp 编辑了包含此问题的问题。该代码用于检查存储在beforeAll 阶段的值。如果未找到,则将其存储并稍后在扩展中检索和使用。两个使用的测试都只是受此扩展影响并执行此代码。
  • 你能创建一个minimal complete verifiable example吗?
  • @MarcPhilipp 编辑了问题,现在有更完整的扩展代码。在两个不同的测试类(两个测试实例)上运行它会产生不同的根上下文实例,因此在调用之间不会保存任何内容。
  • 正如 Sam 在下面所写,这已在 1.0.3 (github.com/junit-team/junit5/issues/1113) 中得到修复,但您应该将 1.1.0 与 Jupiter 5.1.0 一起使用。

标签: java junit junit5


【解决方案1】:

我只是逐字复制了您的 MyExtension(即零更改)并同时运行了 FooTestBarTest

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(MyExtension.class)
class FooTest {

    @Test
    void test() {
    }
}

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(MyExtension.class)
class BarTest {

    @Test
    void test() {
    }
}

结果是:

org.junit.jupiter.engine.descriptor.JupiterEngineExtensionContext@2280cdac
org.junit.jupiter.engine.descriptor.JupiterEngineExtensionContext@2280cdac
Found it, no need to store anything again!

因此,getRoot() 按文档说明工作。

为什么你看到两个不同的根的唯一解释是你必须在不同的进程中执行测试。

请记住,根 ExtensionContext 实例绑定到您的测试套件的当前执行。

因此,如果您在 IDE 中一个接一个地运行 FooTestBarTest,这实际上会导致两个具有不同根目录的“测试套件”。如果您将构建工具配置为在测试类之间fork,情况也是如此。

然而,如果您在一个“测试套件”中同时执行两个测试类(例如,通过告诉您的 IDE 在同一个包或同一个源代码树中运行所有测试),您将看到有一个根,如我在上面提供的输出。

但是请注意,在 1.0.3 版本之前,junit-platform-surefire-provider 存在一个问题,提供者为每个测试类启动了 JUnit 平台。即使 Surefire 实际上并没有启动新的 JVM 进程,这也会产生 forking 的外观。详情请见https://github.com/junit-team/junit5/pull/1137

【讨论】:

  • 感谢您的回答,这很有道理,但它仍然没有揭开我的神秘面纱,这是我创建的最小project on GH。运行它 (mvn clean install) 会显示问题。 junit-platform-surefire-provider 是否有一些幕后的分叉魔术?
  • 您只是使用了错误版本的提供程序。将版本更改为1.1.0 即可解决问题!
猜你喜欢
  • 1970-01-01
  • 2021-03-01
  • 2018-12-21
  • 2019-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多