Spock — первая спецификация
Spock — первая спецификация
Spock — фреймворк тестов на Groovy, который хорошо стыкуется с Java-проектами: production-код на Java, тесты — в src/test/groovy. Spock компилируется в байт-код JVM и запускается через JUnit Platform (та же инфраструктура, что у JUnit 5).
Главная идея — спецификация читается как текст: блоки given (данные), when (действие), then (проверка), таблица where для многих входов.
База Groovy: первая программа · теория: справочник § Spock · Java-тесты: JUnit 5 · сборка: Gradle Groovy DSL.
Что получится
Проект с Java-классом Calc, Spock-спецификацией CalcSpec, запуск ./gradlew test и понимание каждого блока теста.
Термины
| Термин | Простыми словами |
|---|---|
| Specification | Класс теста в Spock (наследник spock.lang.Specification) |
| Feature method | Метод def "описание на русском"() — один сценарий |
Блок given | Подготовка: переменные, моки, фикстуры |
Блок when | Действие: вызов тестируемого кода |
Блок then | Проверки и ожидание исключений |
Блок expect | Действие и проверка в одном шаге |
Блок where | Таблица параметров (как Excel: столбцы = переменные) |
@Unroll | Каждая строка where — отдельный тест в отчёте |
Зачем Spock, если есть JUnit
| JUnit 5 | Spock |
|---|---|
@Test void shouldAdd() | Имя метода = человекочитаемое предложение |
@ParameterizedTest + источники | Таблица where: внизу метода |
| Mockito отдельно | Mock(), Stub() встроены в язык Spock |
| AssertJ / Hamcrest | ==, thrown(), матчеры в then |
Spock не заменяет JUnit в экосистеме: он использует JUnit Platform как раннер. В CI остаётся привычный шаг test и XML-отчёты.
Что тестируем (Java)
Spock вызывает обычные Java-классы без обёрток:
// src/main/java/com/example/Calc.java
package com.example;
public class Calc {
public int add(int a, int b) { return a + b; }
public int divide(int a, int b) {
if (b == 0) throw new ArithmeticException("zero");
return a / b;
}
}
Пакет в тесте Groovy должен совпадать: package com.example.
Gradle (Groovy DSL)
В build.gradle:
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0'
testImplementation 'org.apache.groovy:groovy:4.0.21'
}
test {
useJUnitPlatform()
}
| Зависимость | Зачем |
|---|---|
spock-core | Spock + интеграция с JUnit Platform |
groovy | Компилятор Groovy для тестовых исходников |
useJUnitPlatform() | Gradle запускает тесты через JUnit 5 / Platform |
Папка: src/test/groovy (зеркало пакета com/example/CalcSpec.groovy).
Подробнее про блоки Gradle: 23.md.
Первая спецификация
package com.example
import spock.lang.Specification
import spock.lang.Unroll
class CalcSpec extends Specification {
def calc = new Calc()
def "сложение двух чисел"() {
given:
def a = 2
def b = 3
when:
def result = calc.add(a, b)
then:
result == 5
}
@Unroll
def "деление #a / #b = #expected"() {
expect:
calc.divide(a, b) == expected
where:
a | b | expected
10| 2 | 5
9 | 3 | 3
}
def "деление на ноль бросает исключение"() {
when:
calc.divide(1, 0)
then:
thrown(ArithmeticException)
}
}
Разбор по блокам
Класс и поле:
extends Specification— подключает DSL Spock (блоки, моки,setup/cleanup).def calc = new Calc()— один экземпляр на спецификацию (можно вынести вsetup()).
Сценарий «сложение»:
| Блок | Роль |
|---|---|
given: | Задаём a и b |
when: | Вызываем calc.add |
then: | Утверждение result == 5 (при ложном — провал с diff) |
Параметризованный тест:
@Unroll— в IDE/CI будет «деление 10 / 2 = 5», «деление 9 / 3 = 3», а не одна строка.expect:— когда нет отдельного «действия», только выражение-истина.where:— таблица: столбцыa,b,expectedразделены|.- В имени метода
#a,#b— подстановка значений из строкиwhere.
Исключение:
- В
whenвызываем опасный код. - В
thenthrown(ArithmeticException)— тест зелёный только если исключение именно этого типа вылетело.
Запуск
./gradlew test
Windows: gradlew.bat test.
В IntelliJ IDEA: правый клик на CalcSpec → Run. Отчёт JUnit-совместимый — Jenkins/GitHub Actions подхватят без отдельной настройки Spock.
Успешный прогон в консоли: BUILD SUCCESSFUL, в build/reports/tests/test/index.html — HTML-отчёт.
Моки (кратко)
Зависимость подменяют без Mockito:
def repo = Mock(UserRepository)
repo.findById(1) >> new User(name: "Ann")
when:
def user = service.load(1)
then:
1 * repo.findById(1)
user.name == "Ann"
| Конструкция | Смысл |
|---|---|
Mock(Class) | Прокси: вызовы записываются |
>> значение | Stub: при вызове вернуть значение |
1 * repo.method(...) | Проверка: метод вызван ровно один раз |
Подробнее — справочник.
Частые ошибки
| Симптом | Причина |
|---|---|
| Spec не находится | Файл не в src/test/groovy |
No tests found | Нет useJUnitPlatform() в test { } |
== для объектов «падает» | У POJO нет корректного equals — используйте is() / поля |
| Groovy не компилируется | Несовместимые версии spock-core и groovy (смотрите матрицу на spockframework.org) |
Что попробовать
- Добавить строку в
whereс ожидаемымArithmeticExceptionдляb == 0. - Spock +
@SpringBootTestв Spring-модуле. - Тот же
./gradlew testв Jenkins.
Дальше
Gradle Groovy DSL · Jenkins Pipeline · делегирование · о разделе
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Краткая хронология Groovy на JVM — от идеи James Strachan до ниши Gradle, Jenkins и Spock. Groovy — язык для JVM: тот же байт-код и библиотеки Java, но короче синтаксис, замыкания и скрипты. Набор советов, правил, принципов и обычаев в разработке на этом языке. Простые приложения на Groovy — скрипты на JVM, файлы, JSON и HTTP. Макросы на уровне языка (начиная с Groovy 2.5) — groovy.transform.Macro позволяет инжектить код, основываясь на анализе AST. Статическая и динамическая типизация в Groovy, примитивы JVM, строки GString, коллекции, диапазоны и ключевые операторы def, as, instanceof. Операторы и выражения в Groovy - арифметика, логика и выразительный синтаксис поверх JVM-экосистемы. Циклы и управляющие конструкции Groovy - императивные и декларативные способы описания логики выполнения. В этом примере greet — это переменная, содержащая замыкание. Замыкание принимает один параметр name и выводит приветствие. Вызов greet(Groovy) выполняет код внутри замыкания. Нет проверяемых исключений — компилятор Groovy игнорирует механизм throws, принятый в Java. Динамическая типизация, метапрограммирование, AST-трансформации, DSL, работа с XML и JSON, синтаксический сахар и интеграция с Java. Кавычки, скобки, замыкания, switch, регулярные выражения и truthiness в Groovy.История языка Groovy
Что требуется знать перед началом изучения языка программирования Groovy
Рекомендации по разработке на Groovy
Простые приложения на Groovy
Основы языка Groovy
Типы данных и объявление переменных
Операторы и выражения в Groovy
Циклы и управляющие конструкции
Объектно-ориентированное программирование в Groovy
Иерархия исключений в Groovy
Особенности и расширения языка Groovy
Синтаксис и пунктуация в Groovy