Hi folks, this is my post to get you ready with using Spock testing and specification framework as quickly as possible.

Spock is a great unit testing framework. You can find loads of appreciation for it, & mind you it is indeed worth appreciating.

There are certain prerequisites before using this beautiful framework.

  • What is unit testing and purpose it serves
  • A little bit of Groovy (it is happier Java, as simple), enough to get started with Spock testing
  • Know what are Stubs and Mocks, trust me this one is surely needed

One must understand ‘what is unit testing ?, why unit testing ?’ and its importance in software development, before actually starting to write unit test, be it using any framework.

Lets get started with Spock

Spock was brought to life by Peter Niederwieser( an angel definitely ) as suggested by Wiki.

Spock is what a programming language should look like. It is simple, readable and most importantly understandable to any human. It brings writing business like description to tests. It helps to write specifications for ‘class under test’.

Lets start with a very simple test with Spock

class CalculatorSpec extends spock.lang.Specification {
    def "add must sum two numbers "() {
        when :"a new calculator is created"
            def calculator = new Calculator()
        then :"1 plus 1 is 2"
            calculator.add(1,1) == 2
    }
}

As you can from above spec where Calculator is the class under test, Spock has a very simple structure and speech wherein even a layman can understand what is being proposed.
The ‘def’part is what we are asserting. Here we are asserting ( literal meaning of assert is : to state a fact confidently) that the method ‘add’ should sum given two numbers.

In a standard Maven directory structure, Groovy source code is usually placed in the src/test/groovy folder so that the Groovy compiler plugin can find it. Spock tests can go into this directory without affecting your existing JUnit tests located in src/test/java.

The given,when,then flow

class CalculatorSpec extends spock.lang.Specification {
    def "add must sum two numbers "() {
        given :"a calculator"
            def calculator = new Calculator()
        when :"when 1 is added to 1"
            def sum = calculator.add(1,1)
        then :"sum is 2"
             sum == 2
    }
}

Here you can see, in the given block(usually called as setup block), where a setup is done for the spec.
when block is where a method under test is called then block is where results are checked for truth.

Blocks in a Spock test method

  • given/setup The given/setup(alias for given) block is where all the initialization (preparation) code for unit test resides.
  • when The when block is where the call to our 'method under test' needs to be put. It should be small, and can be as simple as a single line. It is from where the call is triggered to our 'method under test' and its collaborators(stubs i mean to say).
  • then The then block contains assertions ( can be multiple) to test for correctness of our method under test
  • and It is basically to help writes tests in a distinct manner. It makes tests look eye pleasing and brings more natural speech to our tests .
  • cleanup As the name suggests it does the cleanup part. It is similar to 'finally' in the exception handling blocks.
class ListSpec extends spock.lang.Specification {
    def "add items to list "() {
        given :"a list"
            List list = new ArrayList<>()
        when :"when 1 is added to list"
            list.add(1)
        and :"when 2 is added to list" 
            list.add(2)
        then :"size of list is"
            list.size() == 2
        cleanup :"clear list"
            list.clear() 
    }
}



There are many annotations provided in Spock to make specs look more descriptive, but I won’t be covering them as they are not really much needed now.

@Shared This is used to indicate object which we want to ‘live’ across all tests.

class CalculatorSpec extends spock.lang.Specification {
    
    @Shared
    Calculator calculator
    
    def "add numbers "() {        
        setup "give a calculator":
        calculator = new Calculator()
        ...
    }
}



setup() and cleanup() setup() run before each test method. cleanup() run after each test method. They run as many times as test methods exist.

setupSpec() and cleanupSpec() setupSpec() run once before all test methods. cleanupSpec() run once after all test methods. They work only with objects that are either static or marked with the @Shared annotation.

Parameterized Tests Parameterized tests basically stops a developer from repeating their tests. It is very easy to perform with the help of data tables. It basically helps to input for various permutations.

class CalculatorSpec extends spock.lang.Specification {
    def "add must sum two numbers "() {
        when :
            sum = Calculator.add(number1, number2)
        then :
            assert sum
        where:
            number1 | number2   || sum
            1       | 3         || 4
            7       | 4         || 11
            0       | 0         || 0
    }
}



Stubs A stub is a fake class that comes with preprogrammed ( hardcoded in simple terms) return values. It is ‘injected’ into the ‘class under test’ so that there can be a control over the input while the test case is being run.

Mocks A mock is a fake class that can be examined after the test is finished for its ‘interactions’ with the ‘class under test’. It can be used to check how many times a method was called.

Here I would like you to go through the reference documentation of Spock Interaction Based Testing to understand it well as it is a very important topic.

Meanwhile, I would get ready with my added examples and update the post. :) . Adios