Search code examples
testingspockgeb

Spock extension's start method invoked multiple times


I have bunch of functional tests based on Spock and Geb. I want to perform some actions before and after execution of these tests. So I created global extension and added required functionality to start() and stop() methods of that extension. But the problem is that start/stop methods are invoked before/after each Spock spec though Spock documentation (http://spockframework.org/spock/docs/1.1/all_in_one.html#_global_extensions) states:

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

Do I do something wrong or Spock documentation is incorrect about behaviour of these methods?


Solution

  • @MantasG Spock implements a JUnit Runner and does not control how it is executed. Global extensions are managed in a RunContext which is kept in a ThreadLocal. If surefire uses multiple threads to execute Tests then this will create multiple instances of RunContext each with their own list of global extensions. If you are using an EmbeddedSpecRunner then this would also create a new isolated context.

    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.

    Depending on what you want to do there are other ways:

    1. you can use a JUnitRunListener and use the testRunStarted/testRunFinished hooks. Note that you need to register this via surefire.
    2. If you really want to run only once, then you could use failsafe instead of surefire and use the pre- and postintegration goals.
    3. You could hack something using a static fields and a counter for each start/stop call and perform your start action if the counter is 0 and perform your stop action once the counter reaches 0. Of course you'll need to make this thread safe.

    Note that surefire also supports forking multiple JVMs and this will also impact options 1 and 3.