spring-restdocs

示例

  1. 项目结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
➜  spring-rest-docs-demo tree     
.
├── README.md
├── pom.xml
├── spring-rest-docs-demo.iml
└── src
├── main
│   ├── asciidoc
│   │   └── index.adoc
│   ├── java
│   │   └── cn
│   │   └── idea360
│   │   └── docs
│   │   ├── Order.java
│   │   └── SpringRestDocsDemoApplication.java
│   └── resources
│   ├── application.properties
│   ├── static
│   └── templates
└── test
└── java
└── cn
└── idea360
└── docs
└── SpringRestDocsDemoApplicationTests.java
  1. pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.idea360</groupId>
<artifactId>spring-rest-docs-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-rest-docs-demo</name>
<description>公众号[当我遇上你]关于spring rest docs的测试</description>

<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<configuration>
<mainClass>cn.idea360.docs.SpringRestDocsDemoApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>generate-docs</id>
<phase>package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html</backend>
<doctype>book</doctype>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-asciidoctor</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

</project>
  1. index.adoc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
= Java Techie Spring REST Docs Example

This is an example output for a service running at http://localhost:9091:

== POST API Example

.request
include::{snippets}/testAddOrder/http-request.adoc[]

.response
include::{snippets}/testAddOrder/http-response.adoc[]

== GET API Example

.request
include::{snippets}/testGetOrders/http-request.adoc[]

.response
include::{snippets}/testGetOrders/http-response.adoc[]

The data which we can see as part of documentation will loaded from MockMvc Test case data
  1. Order.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package cn.idea360.docs;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Order {

/**
* 订单号
*/
private int orderId;
/**
* 订单名称
*/
private String name;
/**
* 数量
*/
private int quantity;
/**
* 单价
*/
private double price;
}
  1. 启动类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package cn.idea360.docs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RestController
@SpringBootApplication
public class SpringRestDocsDemoApplication {

public static void main(String[] args) {
SpringApplication.run(SpringRestDocsDemoApplication.class, args);
}

/**
* 生成订单
* @param orders 订单信息
* @return 订单信息
*/
@PostMapping("/placeOrder")
public List<Order> saveOrder(@RequestBody List<Order> orders) {
return orders;
}

/**
* 获取订单
* @return 订单清单
*/
@GetMapping("/getOrders")
public List<Order> getOrders() {
return Stream.of(new Order(101, "Mobile", 1, 5700)
,new Order(102, "notebook", 1, 18488))
.collect(Collectors.toList());
}
}
  1. 单元测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package cn.idea360.docs;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.mockito.internal.verification.VerificationModeFactory.description;
import static org.springframework.restdocs.cli.CliDocumentation.curlRequest;
import static org.springframework.restdocs.http.HttpDocumentation.httpRequest;
import static org.springframework.restdocs.http.HttpDocumentation.httpResponse;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.*;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@ExtendWith({ RestDocumentationExtension.class, SpringExtension.class})
@SpringBootTest
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
class SpringRestDocsDemoApplicationTests {

@Autowired
private WebApplicationContext context;

private MockMvc mockMvc;

List<Order> orders=null;

@BeforeEach
public void setUp(WebApplicationContext webApplicationContext,
RestDocumentationContextProvider restDocumentation) {

this.mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation))
.build();

orders= Stream.of(new Order(101, "Mobile", 1, 5700)
,new Order(102, "notebook", 1, 18488))
.collect(Collectors.toList());
}



@Test
public void testAddOrder() throws Exception {
String ordersJson=new ObjectMapper().writeValueAsString(orders);
mockMvc.perform(post("/placeOrder")
.content(ordersJson)
.contentType("application/json")).andDo(print())
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content().json(ordersJson))
.andDo(document("{methodName}",
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint())));
}

@Test
public void testGetOrders() throws Exception {
mockMvc.perform(get("/getOrders")
.contentType("application/json")).andDo(print())
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content().json(new ObjectMapper().writeValueAsString(orders)))
.andDo(document("{methodName}",
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint())));
}

}

参考