Search code examples
groovyjunitspock

How to set up & clean up a resource in Spock for a test suite


I have this code in my JUnit suite:

@RunWith(Suite.class)
@Suite.SuiteClasses({ MyJavaTest.class, MyAnotherJavaTest.class })
public class MyIntegrationSuite {
    @BeforeClass
    public static void beforeTests() throws Exception {
        Container.start();
    }

    @AfterClass
    public static void afterTests() throws Exception {
        Container.stop();
    }
}

I want to rewrite it to Spock, but I can't find any way to do a global setup, only setupSpec() and setup() which is not enough, since I have multiple specifications and I want to start a Container only once.

I tried leaving the suite as it is and passing Spock specifications to it, but the spock tests are skipped entirely (when I add extends Specifications). It's probably, because Specification has @RunWith(Sputnik) and it doesn't play with @RunWith(Suite), but I'm not sure how to get around that.

Is there any way to do a global setup with Spock or execute Spock specifications from JUnit suite?

My pom.xml (stubs are there, because I'm mixing java and groovy code):

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>build-helper-maven-plugin</artifactId>
  <version>${buildhelper.plugin.version}</version>
  <executions>
    <execution>
      <id>add-groovy-test-source</id>
      <phase>test</phase>
      <goals>
        <goal>add-test-source</goal>
      </goals>
      <configuration>
        <sources>
          <source>${basedir}/src/test/groovy</source>
        </sources>
      </configuration>
    </execution>
  </executions>
</plugin>
<plugin>
  <groupId>org.codehaus.gmavenplus</groupId>
  <artifactId>gmavenplus-plugin</artifactId>
  <version>${gmavenplus.plugin.version}</version>
  <executions>
    <execution>
      <goals>
        <goal>generateTestStubs</goal>
        <goal>compileTests</goal>
        <goal>removeTestStubs</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Solution

  • In general, Spock is a JUnit After all (that's why surefire plugin can run it without any additional hassle), so all approaches to the Suites should work, although I haven't used this feature.

    In addition, If you have a "heavy" shared resource, then you might try the following approach:

    abstract class SharedResourceSupport extends Specification {
       def static sharedSource = new SharedSource()
    }
    
    
    class SharedSource {
        public SharedSource() {
            println "Created shared source. Its our heavy resource!"
        }
    }
    
    
    class SpockTest1 extends SharedResourceSupport {
        def "sample test" () {
          expect:
            sharedSource != null
        }
    }
    
    class SpockTest2 extends SharedResourceSupport {
        def "another test" () {
          expect:
            sharedSource != null
        }
    }
    

    Note that the shared resource is defined with "static", so that it will be created only once when the first test will access it.

    As different strategies to deal with this: You might want to consider traits, if your test already inherits from another class, or expose shared resource as a Singleton so that it will guarantee that only one instance exists.

    Try to run both tests and you'll see that that the line "Created shared source..." is called only once