I'm trying to write Spock test cases for my Spring Boot application (version: 2.7.5), and I want to generate AsciiDoc documentation using Spring REST Docs. Can someone provide a sample working code snippet demonstrating how to achieve this?
Here's what I've tried so far:
build.gradle
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 {
...
implementation 'org.springframework.restdocs:spring-restdocs-restassured:2.0.5.RELEASE'
implementation 'org.springframework.restdocs:spring-restdocs-core:2.0.5.RELEASE'
implementation 'org.springframework.restdocs:spring-restdocs-asciidoctor:2.0.5.RELEASE'
testImplementation 'junit:junit:4.13.2'
...
}
test {
outputs.dir snippetsDir
}
asciidoctor {
inputs.dir snippetsDir
dependsOn test
}
LeadControllerSpec
class LeadControllerSpec extends Specification {
@Rule
JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation() // TODO: need to give path
RequestSpecification documentationSpec
void setup() {
this.documentationSpec = new RequestSpecBuilder()
.addFilter(RestAssuredRestDocumentation.documentationConfiguration(restDocumentation)
.operationPreprocessors()
.withRequestDefaults(
Preprocessors.modifyUris().host('api.example.com')
.removePort())
.withResponseDefaults(Preprocessors.prettyPrint()))
.build()
}
void cleanup() {
}
def "test createLead endpoint"() {
when:
def response = RestAssured.given(this.documentationSpec)
.accept(MediaType.APPLICATION_JSON_VALUE)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.body([
firstName: "John",
lastName: "Doe",
mobileNumber: "1234567890",
emailId: "john@example.com",
pincode: "12345",
cardScheme: "SchemeA"
])
.when()
.post("/api/v1/lead/create")
then:
response.statusCode == 200
}
}
Any help would be appreciated. Thanks in advance!
Your code with @Rule
looks like JUnit 4, but Spock 2.x is based on JUnit 5, i.e. that approach probably does not work, unless maybe you are working with Spock 1.x.
I was curious and tried to set up a Maven project from scratch - sorry, please convert it to Gradle by yourself:
https://github.com/kriegaex/SO_Spock_SpringRESTDocs_78424426
The sample application is as follows:
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplication(Application.class).run(args);
}
@RestController
private static class SampleController {
@RequestMapping("/")
public String index() {
return "Hello, World";
}
}
}
The corresponding Spock spec looks like this:
package org.example
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.restdocs.ManualRestDocumentation
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.setup.MockMvcBuilders
import org.springframework.web.context.WebApplicationContext
import spock.lang.Specification
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
@SpringBootTest(classes = [Application])
class MyControllerSpec extends Specification {
def restDocumentation = new ManualRestDocumentation()
@Autowired
WebApplicationContext context
MockMvc mockMvc
def setup() {
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(documentationConfiguration(restDocumentation))
.build()
restDocumentation.beforeTest(getClass(), specificationContext.currentFeature.displayName)
}
def cleanup() {
restDocumentation.afterTest()
}
def "should document the GET /hello endpoint"() {
expect:
mockMvc
.perform(get("/"))
.andExpect(status().isOk())
.andDo(document("sample"))
}
}
Basically, I adjusted the manual setup described in the manual for non-JUnit setups to Spock. From the provided sample project I copied code for TestNG.
It was a bit tricky to make the various product versions for Spring and Spring REST Docs match and also play nice with Spock, but in my sample project it works fine now. The generated HTML page from the asciidoc with included snippets looks as follows:
Disclaimer: Chances are, that my configuration is imperfect and can be improved. But I never used Spring REST Docs before, and I do not even know Spring.