该版本仍在开发中,尚未被视为稳定。对于最新的稳定版本,请使用 spring-cloud-contract 5.0.0!spring-doc.cadn.net.cn

使用 REST 文档

你可以使用 Spring REST 文档生成用于 HTTP API 的文档(例如,Asciidoc格式),使用 Spring MockMvc,WebTestClient 或 RestAssured。在生成 API 文档的同时,你也可以通过使用 Spring Cloud Contract WireMock 生成 WireMock 存根。为此,编写你的普通 REST 文档测试用例并使用@AutoConfigureRestDocs使存根自动生成于REST Docs输出目录中。以下UML图展示了REST 文档流程:spring-doc.cadn.net.cn

休息医生

以下示例使用莫克麦克:spring-doc.cadn.net.cn

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureRestDocs(outputDir = "target/snippets")
@AutoConfigureMockMvc
public class ApplicationTests {

	@Autowired
	private MockMvc mockMvc;

	@Test
	public void contextLoads() throws Exception {
		mockMvc.perform(get("/resource"))
				.andExpect(content().string("Hello World"))
				.andDo(document("resource"));
	}
}

该测试生成一个 WireMock 存根目标/片段/小作品/resource.json. 匹配 都获取/资源路径。 同样的例子是 WebTestClient(用于测试用于测试 Spring WebFlux 应用程序)如下:spring-doc.cadn.net.cn

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureRestDocs(outputDir = "target/snippets")
@AutoConfigureWebTestClient
public class ApplicationTests {

	@Autowired
	private WebTestClient client;

	@Test
	public void contextLoads() throws Exception {
		client.get().uri("/resource").exchange()
				.expectBody(String.class).isEqualTo("Hello World")
 				.consumeWith(document("resource"));
	}
}

无需额外配置,这些测试创建了一个带有请求匹配器的存根用于HTTP方法及除所有头部外主机内容长度. 为了更精确地匹配请求(例如,匹配POST或PUT的正文),我们需要显式创建一个请求匹配器。这样做有两个效果:spring-doc.cadn.net.cn

该功能的主要切入点是WireMockRestDocs.verify(),可以使用 作为文档()方便法,如下 示例如下:spring-doc.cadn.net.cn

import static org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs.verify;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureRestDocs(outputDir = "target/snippets")
@AutoConfigureMockMvc
public class ApplicationTests {

	@Autowired
	private MockMvc mockMvc;

	@Test
	public void contextLoads() throws Exception {
		mockMvc.perform(post("/resource")
                .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
				.andExpect(status().isOk())
				.andDo(verify().jsonPath("$.id"))
				.andDo(document("resource"));
	}
}

前述合同规定,任何有效的POST均为身份证场接收响应 本检验定义。你可以串联调用到.jsonPath()补充一点 匹配者。如果不熟悉 JSON 路径,JayWay 文档可以帮助你快速掌握情况。该测试的WebTestClient版本 有类似的verify()静态辅助器插入同一个位置。spring-doc.cadn.net.cn

而不是jsonPath内容类型方便的方法,你也可以使用 WireMock API 用于验证请求是否与创建的存根匹配,因为 以下示例展示了:spring-doc.cadn.net.cn

@Test
public void contextLoads() throws Exception {
	mockMvc.perform(post("/resource")
               .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
			.andExpect(status().isOk())
			.andDo(verify()
					.wiremock(WireMock.post(urlPathEquals("/resource"))
					.withRequestBody(matchingJsonPath("$.id"))
					.andDo(document("post-resource"))));
}

WireMock API 功能丰富。你可以匹配头部、查询参数和请求体,具体为 正则表达式以及JSON路径。你可以利用这些功能创建更宽的存根 参数范围。前述示例生成了一个类似于以下示例的存根:spring-doc.cadn.net.cn

post-resource.json
{
  "request" : {
    "url" : "/resource",
    "method" : "POST",
    "bodyPatterns" : [ {
      "matchesJsonPath" : "$.id"
    }]
  },
  "response" : {
    "status" : 200,
    "body" : "Hello World",
    "headers" : {
      "X-Application-Context" : "application:-1",
      "Content-Type" : "text/plain"
    }
  }
}
你可以使用其中一种wiremock()方法或jsonPath()contentType()创建请求匹配器的方法,但你不能同时使用这两种方法。

在消费者方面,你可以做出resource.json本节前文生成 在类路径上(例如通过以JAR形式发布存根)。之后,你可以创建一个用 WireMock 在 多种不同的方式,包括使用@AutoConfigureWireMock(stubs=“classpath:resource.json”)如前所述 公文。spring-doc.cadn.net.cn

使用 REST 文档生成合同

你也可以用 Spring REST 生成 Spring Cloud Contract 的 DSL 文件和文档 文档。如果你和Spring Cloud WireMock结合使用,你就能获得两个合约 还有那些小作品。spring-doc.cadn.net.cn

你为什么想用这个功能?社区里有人提问 关于他们希望转向基于DSL的合同定义的情况, 但他们已经有很多春季MVC测试了。利用这个功能可以生成 合同文件,你可以以后修改并迁移到文件夹(定义在你的 配置)以便插件能够找到它们。spring-doc.cadn.net.cn

你可能会好奇为什么这个功能会在WireMock模块里。功能 是因为同时生成合同和存根是合理的。

请考虑以下测试:spring-doc.cadn.net.cn

		this.mockMvc
			.perform(post("/foo").accept(MediaType.APPLICATION_PDF)
				.accept(MediaType.APPLICATION_JSON)
				.contentType(MediaType.APPLICATION_JSON)
				.content("{\"foo\": 23, \"bar\" : \"baz\" }"))
			.andExpect(status().isOk())
			.andExpect(content().string("bar"))
			// first WireMock
			.andDo(WireMockRestDocs.verify()
				.jsonPath("$[?(@.foo >= 20)]")
				.jsonPath("$[?(@.bar in ['baz','bazz','bazzz'])]")
				.contentType(MediaType.valueOf("application/json")))
			// then Contract DSL documentation
			.andDo(document("index", SpringCloudContractRestDocs.dslContract(Maps.of("priority", 1))));

前述测试生成了上一节提出的存根,同时生成两者 合同和一份文件文件。spring-doc.cadn.net.cn

合同称为索引.groovy并且可能类似于以下例子:spring-doc.cadn.net.cn

import org.springframework.cloud.contract.spec.Contract

Contract.make {
    request {
        method 'POST'
        url '/foo'
        body('''
            {"foo": 23 }
        ''')
        headers {
            header('''Accept''', '''application/json''')
            header('''Content-Type''', '''application/json''')
        }
    }
    response {
        status OK()
        body('''
        bar
        ''')
        headers {
            header('''Content-Type''', '''application/json;charset=UTF-8''')
            header('''Content-Length''', '''3''')
        }
        bodyMatchers {
            jsonPath('$[?(@.foo >= 20)]', byType())
        }
    }
}

生成的文档(此处为Asciidoc格式)包含格式化的 合同。该文件的位置为index/dsl-contract.adoc.spring-doc.cadn.net.cn

指定优先级属性

方法SpringCloudContractRestDocs.dslContract()需要一个可选的映射参数,允许你在模板中指定额外的属性。spring-doc.cadn.net.cn

其中一个属性是优先字段,你可以指定如下:spring-doc.cadn.net.cn

SpringCloudContractRestDocs.dslContract(Map.of("priority", 1))

覆盖DSL合同模板

默认情况下,契约的输出基于一个名为的文件default-dsl-contract-only.snippet.spring-doc.cadn.net.cn

你可以通过覆盖getTemplate()方法,提供自定义模板文件,具体如下:spring-doc.cadn.net.cn

new ContractDslSnippet(){
    @Override
    protected String getTemplate() {
        return "custom-dsl-contract";
    }
}));

上面的例子展示了这条线spring-doc.cadn.net.cn

.andDo(document("index", SpringCloudContractRestDocs.dslContract()));
.andDo(document("index", new ContractDslSnippet(){
                            @Override
                            protected String getTemplate() {
                                return "custom-dsl-template";
                            }
                        }));

模板的解析是通过在类路径上查找资源来解决的。以下地点按顺序检查:spring-doc.cadn.net.cn

因此,在上面的例子中,你应该在src/test/resources/org/springframework/restdocs/templates/custom-dsl-template.snippetspring-doc.cadn.net.cn