此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 spring-cloud-contract 4.3.0spring-doc.cadn.net.cn

使用 Stub Runner 启动应用程序

警告

由于当前工件存储库发布工具的限制,我们目前无法发布可执行的 jar 和4.1.6我们将跳过此工件的发布。Stub Runner Boot 仍可通过 Docker Stub Runner Boot 映像获得,这是使用该应用程序的首选方式。您还可以访问项目存储库中的源代码并自行构建应用程序。如果在项目存储库工具中进行了所需的调整,我们将恢复发布此 jar。spring-doc.cadn.net.cn

Spring Cloud Contract Stub Runner Boot 是一个 Spring Boot 应用程序,它将 REST 端点公开给 触发消息传递标签并访问 WireMock 服务器。spring-doc.cadn.net.cn

存根运行器启动安全性

Stub Runner Boot 应用程序在设计上不受保护 - 保护它需要为所有应用程序添加安全性 存根,即使他们实际上不需要它。由于这是一个测试实用程序 - 服务器不打算在生产环境中使用。spring-doc.cadn.net.cn

预计只有受信任的客户端才能访问存根运行器引导服务器。你不应该 在不受信任的位置将此应用程序作为 Fat Jar 或 Docker 映像运行。

存根运行器服务器

要使用 Stub Runner Server,请添加以下依赖项:spring-doc.cadn.net.cn

compile "org.springframework.cloud:spring-cloud-starter-stub-runner"

然后用@EnableStubRunnerServer,建造一个肥大的罐子,它就可以工作了。spring-doc.cadn.net.cn

有关属性,请参阅短截线流道弹簧部分。spring-doc.cadn.net.cn

存根运行器服务器脂肪罐

您可以从 Maven 下载独立的 JAR(例如,对于版本 2.0.1.RELEASE) 通过运行以下命令:spring-doc.cadn.net.cn

$ wget -O stub-runner.jar 'https://search.maven.org/remotecontent?filepath=org/springframework/cloud/spring-cloud-contract-stub-runner-boot/2.0.1.RELEASE/spring-cloud-contract-stub-runner-boot-2.0.1.RELEASE.jar'
$ java -jar stub-runner.jar --stubrunner.ids=... --stubrunner.repositoryRoot=...

Spring Cloud CLI

1.4.0.RELEASESpring Cloud CLI 项目版本,您可以通过运行spring cloud stubrunner.spring-doc.cadn.net.cn

要传递配置,您可以创建一个stubrunner.yml当前工作目录中的文件, 在名为config,或在~/.spring-cloud.该文件可能类似于以下内容 运行本地安装的存根的示例:spring-doc.cadn.net.cn

示例 1.stubrunner.yml
stubrunner:
  stubsMode: LOCAL
  ids:
    - com.example:beer-api-producer:+:9876

然后你可以调用spring cloud stubrunner从终端窗口开始 存根运行器服务器。在端口可用8750.spring-doc.cadn.net.cn

端点

Stub Runner Boot 提供两个端点:spring-doc.cadn.net.cn

HTTP

对于 HTTP,存根运行器启动使以下端点可用:spring-doc.cadn.net.cn

消息

对于消息传递,存根运行器启动使以下端点可用:spring-doc.cadn.net.cn

示例

以下示例显示了 Stub Runner Boot 的典型用法:spring-doc.cadn.net.cn

@SpringBootTest(classes = StubRunnerBoot, properties = "spring.cloud.zookeeper.enabled=false")
@ActiveProfiles("test")
class StubRunnerBootSpec {

	@Autowired
	StubRunning stubRunning

	@BeforeEach
	void setup() {
		RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning),
				new TriggerController(stubRunning))
	}

	@Test
	void 'should return a list of running stub servers in "full ivy port" notation'() {
		when:
			String response = RestAssuredMockMvc.get('/stubs').body.asString()
		then:
			def root = new JsonSlurper().parseText(response)
			assert root.'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs' instanceof Integer
	}

	@Test
	void 'should return a port on which a #stubId stub is running'() {
		given:
		def stubIds = ['org.springframework.cloud.contract.verifier.stubs:bootService:+:stubs',
				   'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs',
				   'org.springframework.cloud.contract.verifier.stubs:bootService:+',
				   'org.springframework.cloud.contract.verifier.stubs:bootService',
				   'bootService']
		stubIds.each {
			when:
				def response = RestAssuredMockMvc.get("/stubs/${it}")
			then:
				assert response.statusCode == 200
				assert Integer.valueOf(response.body.asString()) > 0
		}
	}

	@Test
	void 'should return 404 when missing stub was called'() {
		when:
			def response = RestAssuredMockMvc.get("/stubs/a:b:c:d")
		then:
			assert response.statusCode == 404
	}

	@Test
	void 'should return a list of messaging labels that can be triggered when version and classifier are passed'() {
		when:
			String response = RestAssuredMockMvc.get('/triggers').body.asString()
		then:
			def root = new JsonSlurper().parseText(response)
			assert root.'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs'?.containsAll(["return_book_1"])
	}

	@Test
	void 'should trigger a messaging label'() {
		given:
			StubRunning stubRunning = Mockito.mock(StubRunning)
			RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning), new TriggerController(stubRunning))
		when:
			def response = RestAssuredMockMvc.post("/triggers/delete_book")
		then:
			response.statusCode == 200
		and:
			Mockito.verify(stubRunning).trigger('delete_book')
	}

	@Test
	void 'should trigger a messaging label for a stub with #stubId ivy notation'() {
		given:
			StubRunning stubRunning = Mockito.mock(StubRunning)
			RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning), new TriggerController(stubRunning))
		and:
			def stubIds = ['org.springframework.cloud.contract.verifier.stubs:bootService:stubs', 'org.springframework.cloud.contract.verifier.stubs:bootService', 'bootService']
		stubIds.each {
			when:
				def response = RestAssuredMockMvc.post("/triggers/$it/delete_book")
			then:
				assert response.statusCode == 200
			and:
				Mockito.verify(stubRunning).trigger(it, 'delete_book')
		}

	}

	@Test
	void 'should throw exception when trigger is missing'() {
		when:
		BDDAssertions.thenThrownBy(() -> RestAssuredMockMvc.post("/triggers/missing_label"))
		.hasMessageContaining("Exception occurred while trying to return [missing_label] label.")
		.hasMessageContaining("Available labels are")
		.hasMessageContaining("org.springframework.cloud.contract.verifier.stubs:loanIssuance:0.0.1-SNAPSHOT:stubs=[]")
		.hasMessageContaining("org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs=")
	}

}

使用服务发现的存根运行器启动

使用 Stub Runner Boot 的一种方法是将其用作“冒烟测试”的存根源。那是什么意思? 假设您不想按顺序将 50 个微服务部署到测试环境 以查看您的应用程序是否有效。在构建过程中,你已经运行了一套测试, 但您还希望确保应用程序的打包有效。您可以 将应用程序部署到环境,启动它,然后对其运行几个测试,看看是否 它有效。我们可以将这些测试称为“烟雾测试”,因为它们的目的只是检查少数几个 测试场景。spring-doc.cadn.net.cn

这种方法的问题在于,如果您使用微服务,您很可能还会 使用服务发现工具。Stub Runner Boot 允许您通过启动 必需的存根,并在服务发现工具中注册它们。spring-doc.cadn.net.cn

现在假设我们要启动此应用程序,以便自动注册存根。 我们可以通过使用java -jar ${SYSTEM_PROPS} stub-runner-boot-eureka-example.jar哪里${SYSTEM_PROPS}.spring-doc.cadn.net.cn

这样,部署的应用程序可以通过服务向已启动的 WireMock 服务器发送请求 发现。最有可能的是,默认情况下可以设置点 1 到 3application.yml,因为它们不是 可能会改变。这样,您就可以在启动时仅提供要下载的存根列表 短滑道靴子。spring-doc.cadn.net.cn