多次调用 Spock 扩展的启动方法

Spock extension's start method invoked multiple times

我有一堆基于 Spock 和 Geb 的功能测试。我想在执行这些测试之前和之后执行一些操作。所以我创建了全局扩展并向该扩展的 start() 和 stop() 方法添加了所需的功能。但问题是 start/stop 方法被调用 before/after 每个 Spock 规范虽然 Spock 文档 (http://spockframework.org/spock/docs/1.1/all_in_one.html#_global_extensions) 指出:

start() This is called once at the very start of the Spock execution

stop() This is called once at the very end of the Spock execution

是我做错了什么,还是 Spock 文档关于这些方法的行为不正确?

我相信 Spock 在您的测试套件中的每个测试规范开始时都会被调用,因此每次执行

的开始和停止都是 运行

我想您可能想看看在您在问题中链接的同一文档中找到的 Fixture Methods: http://spockframework.org/spock/docs/1.1/all_in_one.html#_specification

@MantasG Spock 实现了一个 JUnit Runner 并且不控制它的执行方式。全局扩展在 RunContext 中管理,保存在 ThreadLocal 中。如果 surefire 使用多个线程来执行测试,那么这将创建 RunContext 的多个实例,每个实例都有自己的全局扩展列表。如果您使用的是 EmbeddedSpecRunner 那么这也会创建一个新的独立上下文。

This context will stay around until the thread dies. It would be more accurate to remove the context once the test run has finished, but the JUnit Runner SPI doesn't provide an adequate hook. That said, since most environments fork a new JVM for each test run, this shouldn't be much of a problem in practice.

根据你想做什么,还有其他方法:

  1. 您可以使用 JUnitRunListener 并使用 testRunStarted/testRunFinished 挂钩。请注意,您需要通过 surefire 进行注册。
  2. 如果你真的只想 运行 一次,那么你可以使用故障保护而不是万无一失,并使用前后集成目标。
  3. 您可以使用静态字段和每个 start/stop 调用的计数器进行破解,如果计数器为 0 则执行开始操作,一旦计数器达到 0 则执行停止操作. 当然你需要确保这个线程安全。

请注意,surefire 也支持 forking multiple JVMs,这也会影响选项 1 和 3。