the enterprise-ready specification framework
Spock is a testing, specification, and mocking framework for JVM developers that emphasizes readability and clarity. By blending BDD concepts and Groovy's concise syntax, Spock helps teams write tests that are easy to understand and enjoyable to maintain.
Write tests that are easy to read and understand, even for non-programmers.
Create flexible and powerful mocks and stubs with built-in support.
Seamless integration with JUnit 5+ and build tools.
Easily run the same test with different sets of data.
Leverage the power and flexibility of the Groovy language.
Use a rich set of matchers to verify expectations with clarity.
// CalculatorSpec.groovy
import spock.lang.Specification
class CalculatorSpec extends Specification {
def "Test calculate method: #a #operation #b = #expectedResult"() {
given: "A calculator instance"
def calculator = new Calculator()
expect: "The calculation should match the expected value"
calculator.calculate(a, b, operation) == expectedResult
where: "Define test data"
a | b | operation || expectedResult
1 | 2 | "+" || 3
5 | 3 | "-" || 2
4 | 2 | "*" || 8
10 | 2 | "/" || 5
-1 | 1 | "+" || 0
1 | -1 | "-" || 2
-2 | -2 | "*" || 4
-4 | -2 | "/" || 2
1 | 1 | "+" || 42 // A failing test case
}
def "Test calculate method with division by zero"() {
given: "A calculator instance"
def calculator = new Calculator()
when: "Perform division by zero"
calculator.calculate(10, 0, "/")
then: "An IllegalArgumentException is thrown"
def exception = thrown(IllegalArgumentException)
and: "The exception message is correct"
exception.message == "Cannot divide by zero"
}
def "Test calculate method with invalid operation"() {
given: "A calculator instance"
def calculator = new Calculator()
when: "Perform calculation with invalid operation"
calculator.calculate(1, 2, "**")
then: "An IllegalArgumentException is thrown"
def exception = thrown(IllegalArgumentException)
and: "The exception message is correct"
exception.message == "Invalid operation: **"
}
}
// Calculator.groovy
class Calculator {
/**
* Performs arithmetic operations on two integers.
*
* @param a The first integer.
* @param b The second integer.
* @param operation The operation to perform (+, -, *, /).
* @return The result of the operation.
* @throws IllegalArgumentException if the operation is invalid or division by zero is attempted.
*/
int calculate(int a, int b, String operation) {
switch (operation) {
case "+": return a + b
case "-": return a - b
case "*": return a * b
case "/":
if (b == 0) {
throw new IllegalArgumentException("Cannot divide by zero")
}
return a / b
default:
throw new IllegalArgumentException("Invalid operation: " + operation)
}
}
String toString() {
return "Calc"
}
}
Spock's clear given:, when:, then: blocks make understanding test logic intuitive.
╷
└─ Spock ✔
└─ CalculatorSpec ✔
├─ Test calculate method: #a #operation #b = #expectedResult ✔
│ ├─ Test calculate method: 1 + 2 = 3 ✔
│ ├─ Test calculate method: 5 - 3 = 2 ✔
│ ├─ Test calculate method: 4 * 2 = 8 ✔
│ ├─ Test calculate method: 10 / 2 = 5 ✔
│ ├─ Test calculate method: -1 + 1 = 0 ✔
│ ├─ Test calculate method: 1 - -1 = 2 ✔
│ ├─ Test calculate method: -2 * -2 = 4 ✔
│ ├─ Test calculate method: -4 / -2 = 2 ✔
│ └─ Test calculate method: 1 + 1 = 42 ✘ Condition not satisfied:
│
│ calculator.calculate(a, b, operation) == expectedResult
│ | | | | | | |
│ Calc 2 1 1 + | 42
│ false
├─ Test calculate method with division by zero ✔
└─ Test calculate method with invalid operation ✔