Why do I need to use Spock framework?

Today we have many excellent frameworks that we can use to test our code, some are breadth known that uses JUnit 4 rules, others that include Hamcrest with JUnit 5 and that makes the job to cover the code with Unit Tests, Integration Tests, Functional Tests, etc.

Then, Why do I need to change of tech if what I’m using is enough? Well, First of all It’s always important to look at other technologies to explore the benefits and to directly answer the question, there are other technologies that made an effort to improve readability in your test code and also let it simpler.

For example, in the official Spock’s repository https://github.com/spockframework/spock-example/tree/master/src/test/groovy there are many Groovy samples that I found useful to start, I copied one example only to show how the code is easier to read:

import spock.lang.Specification

import static spock.util.matcher.HamcrestMatchers.closeTo

/**
 * Hamcrest matchers are deeply integrated with Spock's condition mechanism.
 * The syntax for using a matcher in a condition is simple:
 * {@code <expected-value> <matcher>}. If the condition fails, both the usual
 * condition output and the matcher's output will be shown.
 *
 * @author Peter Niederwiser
 * @since 0.5
 */
class HamcrestMatchersSpec extends Specification {
  def "comparing two decimal numbers"() {
    def myPi = 3.14

    expect:
    myPi closeTo(Math.PI, 0.01)
  }
}

I have other samples I wrote in SpringBoot-Spock repository to show how to use the Given / When / Then structure and to show how the code looks like:

class SampleServiceTest extends Specification {

    SampleService sampleService
    SampleRepository sampleRepository

    def setup() {
        sampleRepository = Mock()
        sampleService = new SampleService(sampleRepository: sampleRepository)
    }

    def "validate getSample with data"() {
        given:
        def title = "world"
        SampleEntity sampleEntity = new SampleEntity(id: 5, title:'sampleA', rate: 2.45)
        1 * sampleRepository.getByTitle(title) >> Optional.of(sampleEntity)

        when:
        SampleEntity sampleEntityResponse = sampleService.getSample(title)

        then:
        sampleEntityResponse.rate == sampleEntity.rate

    }

    def "validate getSample without data"() {
        given:
        def title = "anyTitle"
        1 * sampleRepository.getByTitle(title) >> Optional.ofNullable()

        when:
        SampleEntity sampleEntityResponse = sampleService.getSample(title)

        then:
        sampleEntityResponse == null

    }

}

I know that using JUnit these tests could be written with some more lines of code, but the Spock framework includes validations for every phase that makes it a bit more interesting. I know there is no tool that is better at everything, but some tools are better for specific goals, and in my opinion, Spock helps on the goal to let your code in a cleaner way.

I hope it helps!