You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Spock与Spring REST Docs生成AsciiDoc接口文档求助

修正后的完整可运行示例

1. 调整build.gradle配置

修正依赖作用域,添加Spock Spring支持,完善Asciidoctor配置:

plugins { 
    id 'org.springframework.boot' version '2.7.5'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
    id 'groovy'
    id "org.asciidoctor.convert" version "1.5.8.1"
}

group = 'co.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
    mavenCentral()
}

ext {
    snippetsDir = file('build/generated-snippets')
}

dependencies {
    // Spring Boot Web核心依赖
    implementation 'org.springframework.boot:spring-boot-starter-web'
    
    // Spock测试框架依赖
    testImplementation 'org.spockframework:spock-core:2.0-groovy-3.0'
    testImplementation 'org.spockframework:spock-spring:2.0-groovy-3.0'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    
    // Spring REST Docs依赖(仅测试阶段使用,必须用testImplementation)
    testImplementation 'org.springframework.restdocs:spring-restdocs-restassured:2.0.5.RELEASE'
    testImplementation 'org.springframework.restdocs:spring-restdocs-core:2.0.5.RELEASE'
    testImplementation 'org.springframework.restdocs:spring-restdocs-asciidoctor:2.0.5.RELEASE'
}

test { 
    outputs.dir snippetsDir
    // 启用JUnit 4兼容模式,适配RestDocumentationRule
    useJUnitPlatform()
}

asciidoctor { 
    inputs.dir snippetsDir 
    dependsOn test 
    // HTML文档输出目录
    outputs.dir file('build/asciidoc')
}

2. 完善Spock测试类(LeadControllerSpec)

添加Spring上下文配置、端口绑定和文档生成逻辑:

import groovy.json.JsonBuilder
import org.junit.Rule
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.web.server.LocalServerPort
import org.springframework.http.MediaType
import org.springframework.restdocs.RestDocumentationRule
import org.springframework.restdocs.payload.JsonFieldType
import org.springframework.restdocs.restassured.RestAssuredRestDocumentation
import org.springframework.restdocs.restassured.document
import org.springframework.restdocs.payload.fieldWithPath
import org.springframework.restdocs.preprocess.Preprocessors
import io.restassured.RestAssured
import io.restassured.builder.RequestSpecBuilder
import io.restassured.specification.RequestSpecification
import spock.lang.Specification

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class LeadControllerSpec extends Specification {

    @LocalServerPort
    int localServerPort

    // 指定snippets输出路径,与build.gradle配置一致
    @Rule
    RestDocumentationRule restDocumentation = new RestDocumentationRule("build/generated-snippets")

    RequestSpecification documentationSpec

    void setup() {
        // 绑定Spring Boot随机端口
        RestAssured.port = localServerPort

        this.documentationSpec = new RequestSpecBuilder()
                .addFilter(RestAssuredRestDocumentation.documentationConfiguration(restDocumentation)
                        .operationPreprocessors()
                        .withRequestDefaults(
                                Preprocessors.modifyUris().host('api.example.com').removePort(),
                                Preprocessors.prettyPrint())
                        .withResponseDefaults(Preprocessors.prettyPrint()))
                .build()
    }

    def "test createLead endpoint"() {
        given:
        def requestBody = new JsonBuilder([
                firstName: "John",
                lastName: "Doe",
                mobileNumber: "1234567890",
                emailId: "john@example.com",
                pincode: "12345",
                cardScheme: "SchemeA"
        ]).toString()

        when:
        def response = RestAssured.given(this.documentationSpec)
                .accept(MediaType.APPLICATION_JSON_VALUE)
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .body(requestBody)
                // 生成接口文档片段
                .filter(document("create-lead",
                        requestFields(
                                fieldWithPath("firstName").type(JsonFieldType.STRING).description("联系人名字"),
                                fieldWithPath("lastName").type(JsonFieldType.STRING).description("联系人姓氏"),
                                fieldWithPath("mobileNumber").type(JsonFieldType.STRING).description("手机号码"),
                                fieldWithPath("emailId").type(JsonFieldType.STRING).description("邮箱地址"),
                                fieldWithPath("pincode").type(JsonFieldType.STRING).description("邮政编码"),
                                fieldWithPath("cardScheme").type(JsonFieldType.STRING).description("卡组织类型")
                        ),
                        responseFields(
                                fieldWithPath("id").type(JsonFieldType.NUMBER).description("生成的Lead ID"),
                                fieldWithPath("status").type(JsonFieldType.STRING).description("请求状态"),
                                fieldWithPath("message").type(JsonFieldType.STRING).description("提示信息")
                        )
                ))
                .when()
                .post("/api/v1/lead/create")

        then:
        response.statusCode == 200
    }
}

3. 创建AsciiDoc模板文件

在src/docs/asciidoc目录下创建index.adoc,整合自动生成的文档片段:

= Lead API 接口文档
:toc: left
:toclevels: 3

== 创建Lead接口

=== 请求示例
include::{snippets}/create-lead/http-request.adoc[]

=== 请求参数说明
include::{snippets}/create-lead/request-fields.adoc[]

=== 响应示例
include::{snippets}/create-lead/http-response.adoc[]

=== 响应参数说明
include::{snippets}/create-lead/response-fields.adoc[]

4. 生成完整文档

执行Gradle命令生成HTML文档:

./gradlew asciidoctor

生成的HTML文档路径为build/asciidoc/html5/index.html,直接打开即可查看格式化后的接口文档。

关键修正说明

  • 依赖作用域:Spring REST Docs依赖必须设置为testImplementation,仅在测试阶段生效
  • 路径一致性:RestDocumentationRule指定的路径必须与build.gradle中snippetsDir完全一致,确保片段生成到正确位置
  • Spring上下文:通过@SpringBootTest启用Spring容器,@LocalServerPort绑定随机端口避免冲突
  • 文档生成逻辑:通过.filter(document(...))明确指定要记录的请求/响应字段,确保接口细节被完整记录

内容的提问来源于stack exchange,提问作者vamsi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 18:35:08