Skip to content

Spock 2

There is no special extensions for Spock 2 (like it was for spock 1), instead I did an extra integration library, so you can use existing Junit 5 extensions with spock.

Note

You are not limited to guicey junit 5 extensions, you can use (almost) any junit 5 extensions. And you can use any other spock extensions together with junit extensions.

Setup

You will need the following dependencies (assuming BOM used for versions management):

testImplementation 'ru.vyarus:spock-junit5'
testImplementation 'org.spockframework:spock-core:2.1-groovy-3.0'
testImplementation 'io.dropwizard:dropwizard-testing'
testImplementation 'org.junit.jupiter:junit-jupiter-api'

Note

In gradle you need to explicitly activate junit 5 support with

test {
    useJUnitPlatform()
    ...
}                    

Usage

See junit 5 extensions docs for usage details (it's all used the same).

Warning

Junit 5 extensions would not work with @Shared spock fields! You can still use such fields directly, but don't expect junit 5 extensions to be able to work with such fields (they can't "see" it).

Here is a simple example:

@TestDropwizardApp(App)
class MyTest extends Specification {

    @Inject MyService service

    def "Check something" (ClientSupport client) {

        when: "calling rest endpoint"
        def res = client.targetRest("foo/bar").request()
                .buildGet().invoke().readEntity(String)

        then: "result correct"
        res == "something"

        and: "service called"
        service.isCalled()
    }
}

Tip

Note that parameter injection will also work in test and fixture (setup/cleanup) methods

Overall, you get best of both worlds: same extensions as in junit 5 (and ability to use all other junit extensions) and spock expressiveness for writing tests.

Special cases

Junit 5 doc describes system stubs library usage. It is completely valid for spock, I'll just show a few examples here on how to:

  • Modify (and reset) environment variables
  • Modify (and reset) system properties
  • Validate system output (e.g. testing logs)
  • Intercepting system exit
@ExtendWith(SystemStubsExtension)
class StartupErrorTest extends Specification {

    @SystemStub
    SystemExit exit
    @SystemStub
    SystemErr err

    def "Check app crash"() {

        when: "starting app"
        exit.execute(() -> {
            new App().run(['server'] as String[])
        });

        then: "error"
        exit.exitCode == 1
        err.text.contains("Error message text")
    }
}
@ExtendWith(SystemStubsExtension)
class EnvironmentChangeTest extends Specification {

    @SystemStub
    EnvironmentVariables ENV
    @SystemStub
    SystemOut out
    @SystemStub
    SystemProperties propsReset

    def "Check variables mapping"() {

        setup:
        ENV.set("VAR", "1")
        System.setProperty("foo", "bar") // OR propsReset.set("foo", "bar") - both works the same

        when: 
        // something requiring custom env or property values

        then:
        // validate system output (e.g. logs correctness)
        out.text.contains("Some message assumed to be logged")

Note

Use test framework-agnostic utilities to run application with configuration or to run application without web part (for faster test).