Search code examples
groovyjunittraitsspock

Spock - setup spec with groovy trait and @BeforeClass


I was trying to setup a common array of objects which are loaded and deserialised from json file in resources and tried to do this by using groovy trait with setup() method.

Trait:

Object[] arr

@BeforeClass
def setupTrait() {
   arr = loadFromFile("xxx.json")
}

Test:

def setup() {}

def "test"() {
   arr.size() //here arr is null, although the setup in groovy is called
}

Working solution.

Trait:

static Object[] arr = loadFromFile("xxx.json")

Test:

def setup() {}

def "test"() {
   arr.size() //here arr is ok.
}

The question is why the first isn't working right? If I use @Before annotation and arr is loaded before each test, it's somehow working...


Solution

  • There are some minor mistakes that I suggest to rewrite in a more "spock"-y way:

    • in spock you're supposed to use def setupSpec() fixture method and not @BeforeClass
    • if you want to initialize a variable in setupSpec that indeed will run only once for all test cases you are supposed to put @Shared annotation on the field.

    But then, even if the code will look like this:

    trait SampleTrait {
        @Shared List arr
        def setupSpec() {
            arr = [1,2,3]
        }
    }
    

    It still doesn't work. Now, It looks like you've encountered an open issue in spock:

    https://github.com/spockframework/spock/issues/83

    The issue is open, but the workaround exists and is suggested in the discussion: put a word static (you have actually done that :)). The reason: @Shared annotation cannot be processed by Spock when they appear in traits.

    So, all-in-all I believe the best you can get is:

    trait SampleTrait {
        static List arr
    
        def setupSpec() {
            arr = [1,2,3]
        }
    }
    
    class SampleTestSpec extends Specification implements SampleTrait {
        def "list equality"() {
            expect:
              arr == [1,2,3]
        }
    }