Learn Groovy - Testing & Quality
Series/Learn Groovy/Episode 11
Episode 11 of 23

Learn Groovy - Testing & Quality

This episode covers unit testing with Spock and JUnit, including mocking, data-driven tests, and behavior-driven syntax. You will also learn static type checking and linting to keep Groovy code quality high from the editor onward.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Code without tests is technical debt that silently accumulates. Episode 11 takes you into testing practices in the Groovy ecosystem, with a focus on Spock — a testing framework born for Groovy that has become the de facto standard in JVM projects.

You'll learn unit testing with Spock and JUnit, mocking, data-driven tests, behavior-driven syntax, as well as static type checking and linting to keep code quality high.

Unit Testing with Spock

Getting to Know Spock

Spock uses Groovy as its test language, so tests are written in .groovy files. Spock's basic structure consists of given, when, and then blocks that separate setup, action, and verification:

Basic Spock specification
import spock.lang.Specification
 
class KalkulatorSpec extends Specification {
    def "menjumlahkan dua angka"() {
        given:
        def kalkulator = new Kalkulator()
 
        when:
        def hasil = kalkulator.tambah(2, 3)
 
        then:
        hasil == 5
    }
}

class KalkulatorSpec extends Specification makes the class a Spock test. def "menjumlahkan dua angka"() is a test method name that can be a full sentence — that's the hallmark of behavior-driven syntax.

Running Tests

Spock runs on top of JUnit, so tests can be executed with any build tool:

Run Spock tests
gradle test

gradle test runs all tests in the project, including Spock specs and JUnit tests. The result is HTML and XML reports that can be integrated into a CI/CD pipeline — a topic we'll dive into in episode 13.

Data-Driven Tests

The where Block

Spock's main strength is data-driven testing. A single test method can run with many data combinations through the where block:

Spock data-driven test
import spock.lang.Specification
 
class KalkulatorSpec extends Specification {
    def "penjumlahan dengan berbagai input"() {
        expect:
        a + b == hasil
 
        where:
        a | b || hasil
        1 | 2 || 3
        5 | 5 || 10
        -1 | 1 || 0
    }
}

where: provides a data table with || separating input from expectation. a | b || hasil defines the column headers, and each following row is one test case. If a row fails, Spock reports which row is problematic.

Mocking

Mocking with Spock

Mocks allow a test to isolate a unit of code from external dependencies such as databases or APIs:

Mocking with Spock
import spock.lang.Specification
 
class LayananSpec extends Specification {
    def "mengambil data dari repository mock"() {
        given:
        def repo = Mock(Repositori)
        def layanan = new Layanan(repo)
        repo.cari(1) >> "data-1"
 
        when:
        def hasil = layanan.ambil(1)
 
        then:
        hasil == "data-1"
        1 * repo.cari(1)
    }
}

Mock(Repositori) creates a fake object, and repo.cari(1) >> "data-1" configures the return value. 1 * repo.cari(1) is interaction verification — ensuring the method was called exactly once with specific arguments.

Interactions and Stubbing

Spock distinguishes two concepts:

  • Stubbing: specifying the return value, written with >>.
  • Interactions: verifying the call count, written with 1 *.

Both can be combined in a single expression. This pattern makes Spock tests express intent clearly, something that in JUnit requires an additional library like Mockito.

Static Type Checking and Linting

@CompileStatic

Groovy is dynamic, but type checking can be enabled at compile time with @CompileStatic:

Static type checking
import groovy.transform.CompileStatic
 
@CompileStatic
class Layanan {
    String sapa(String nama) {
        "Halo, ${nama}!"
    }
}

@CompileStatic makes the Groovy compiler check types like Java. import groovy.transform.CompileStatic speeds up execution while catching type errors at compile time — the performance trade-off will be covered in episode 16.

Groovy Lint

To check style and potential bugs, use a lint tool:

Lint Groovy code
npm-groovy-lint --path src/main/groovy

npm-groovy-lint --path src/main/groovy runs a CodeNarc-based checker that detects code smells and style violations. Integrate linting into CI so every pull request passes automatic checks.

Closing

Episode 11 equipped you with the foundations of Groovy testing: Spock with given/when/then blocks, data-driven tests with where, mocking and interaction verification, as well as static type checking and linting for code quality.

The key takeaways:

  • Spock uses Groovy and runs on top of JUnit.
  • The given/when/then blocks separate setup, action, and verification.
  • Data-driven tests use a where table with many cases.
  • Mock creates fake objects; >> configures return values.
  • 1 * method verifies the interaction count.
  • @CompileStatic adds type safety and execution speed.

In episode 12 next, we'll discuss Gradle and build automation — Groovy build scripts in build.gradle, custom tasks, plugins, dependency management, and multi-module projects.

Learn Groovy - Testing & Quality | Learn Groovy