Boost API Test Efficiency with Groovy, Spock, and RestAssured
This article compares a Java + TestNG + HttpClient stack with a Groovy + Spock + RestAssured approach, showing how data‑driven testing, encryption handling, data extraction, and validation can be streamlined for more flexible and efficient API testing.
Background: As business complexity grows, API testing needs improvements in data construction, case structure, parameter extraction, and validation to achieve flexible, scenario‑based, and efficient test cases.
The test project switched from a Java + TestNG + HttpClient framework to Groovy + Spock + RestAssured, and the article compares both approaches across various scenarios.
Optimization Scenarios
1.1 Data‑Driven Testing
The original approach used TestNG dataProvider with CSV files, which struggled with complex data such as dictionaries or data from previous APIs. The new approach allows direct data creation in code, reading from databases or APIs, and flexible record merging.
Examples of data sources: reading from an API, writing data tables in code.
1.2 Interface Encryption
Some services require Gzip, PB, H5, or Flash encryption. The original solution used caseId checks and static variables to decide encryption. The refactored solution uses given/expect blocks to request data and specify decryption methods.
1.3 Data Extraction
The previous method extracted the full response as a string or required custom parsing. The new method leverages RestAssured and Groovy to implicitly determine data format from response headers, offering rich extractors for body, headers, status line, and supporting filtering, grouping, and processing of extracted data.
1.4 Data Validation
Original validation relied on large JSON file comparison and custom checkRepContext methods. The improved solution uses Groovy, Spock, and RestAssured features, supporting Hamcrest assertions, chained multi‑level assertions, and custom configurations for flexible validation.
1.5 Other Enhancements
Includes Allure report customizations and interface polling.
Appendix
2.1 Groovy Basics
Groovy runs on the JVM, is compatible with Java syntax, and supports both static and dynamic typing. It offers range types, list and map literals, type inference with
def, default method parameters, and string interpolation using
$varor
${expr}.
2.2 Spock Framework
Spock is a modern, expressive testing framework for Java and Groovy. Test classes extend
Specificationand contain shared fields, fixture methods (
setup,
cleanup,
setupSpec,
cleanupSpec), and feature methods composed of blocks such as
given,
when,
then,
expect,
where, and optional
and. Annotations like
@Stepwise,
@Unroll, and
@Sharedcontrol execution order and data‑driven behavior.
<code>class OneTestSpec extends Specification {
// fields
// fixture methods
// feature methods
}</code>Feature methods can be data‑driven using the
whereblock with data pipes, tables, or variable assignments, optionally combined with
@Unrollfor test expansion.
<code>// Data pipe example
@Rollup
def "data pipe: #a and #b max is #c"() {
expect: Math.max(a, b) == c
where:
a << [3, 5, 9]
b << [7, 4, 9]
c << [7, 5, 9]
}</code> <code>// Data table example
@Unroll
def "data table: #a and #b min is #c"() {
expect: Math.min(a, b) == c
where:
a | b || c
3 | 7 || 3
5 | 4 || 4
9 | 9 || 9
}</code>2.3 RestAssured
RestAssured is a lightweight Java library for REST API testing. It follows a
given‑when‑thensyntax, supports request parameterization, response extraction, and Hamcrest‑based assertions.
<code>def "simple get request"() {
setup:
given().get("/demo")
}</code> <code>def "standard format"() {
given()
.log().all()
.queryParams([key1: "mp3", key2: "mp4"])
.body([key1: "mp3", key2: "mp4"])
.when()
.post("/demo")
.then()
.log().all()
.statusCode(200)
}</code> <code>def "response assertions"() {
given().get("/demo").then()
.statusCode(200)
.contentType(ContentType.JSON)
.body("params", notNullValue())
.body("params.findAll {['W','D'].contains(it.paramName)}.collect {it.subMap(['paramName','displayName','value'])}",
equalToJson([
[paramName: "W", displayName: "宽度", value: "600"],
[paramName: "D", displayName: "深度", value: "500"]
]))
}</code> <code>def "automatic encryption/decryption"() {
given()
.log().all()
.filters([new H5EncryptRequestFilter(), new H5EncryptResponseFilter()])
.body([k: "v"])
.post("/demo")
.then().log().all()
}</code>Qunhe Technology Quality Tech
Kujiale Technology Quality
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.