Using the Pluggable Architecture

您可能会遇到您的合同以其他格式定义的情况,例如 YAML、RAML 或 PACT。在这些情况下,您仍然希望利用生成测试和存根的自动化功能。您可为测试和存根的生成添加您自己的实现。此外,您可以自定义生成测试的方式(例如,您可以生成其他语言的测试)和生成存根的方式(例如,您可以生成其他 HTTP 服务器实现的存根)。

You may encounter cases where your contracts have been defined in other formats, such as YAML, RAML, or PACT. In those cases, you still want to benefit from the automatic generation of tests and stubs. You can add your own implementation for generating both tests and stubs. Also, you can customize the way tests are generated (for example, you can generate tests for other languages) and the way stubs are generated (for example, you can generate stubs for other HTTP server implementations).

Custom Contract Converter

ContractConverter 接口允许您注册您自己的合同结构转换器实现。以下代码清单演示了 ContractConverter 接口:

The ContractConverter interface lets you register your own implementation of a contract structure converter. The following code listing shows the ContractConverter interface:

Unresolved directive in pluggable-architecture.adoc - include::{contract_spec_path}/src/main/java/org/springframework/cloud/contract/spec/ContractConverter.java[]

您的实现必须定义它应开始转换的条件。另外,您必须定义如何在两个方向执行转换。

Your implementation must define the condition on which it should start the conversion. Also, you must define how to perform that conversion in both directions.

创建实现后,您必须创建一个 /META-INF/spring.factories 文件,其中提供您实现的完全限定名称。

Once you create your implementation, you must create a /META-INF/spring.factories file in which you provide the fully qualified name of your implementation.

以下示例演示了一个典型的 spring.factories 文件:

The following example shows a typical spring.factories file:

org.springframework.cloud.contract.spec.ContractConverter=\
org.springframework.cloud.contract.verifier.converter.YamlContractConverter

Using the Custom Test Generator

如果您想要生成 Java 以外的语言的测试或者您对验证者生成 Java 测试的方式不满意,您可以注册您自己的实现。

If you want to generate tests for languages other than Java or you are not happy with the way the verifier builds Java tests, you can register your own implementation.

SingleTestGenerator 接口允许您注册您自己的实现。以下代码清单演示了 SingleTestGenerator 接口:

The SingleTestGenerator interface lets you register your own implementation. The following code listing shows the SingleTestGenerator interface:

Unresolved directive in pluggable-architecture.adoc - include::{verifier_root_path}/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java[]

同样,您必须提供一个 spring.factories 文件,例如以下示例中所示:

Again, you must provide a spring.factories file, such as the one shown in the following example:

org.springframework.cloud.contract.verifier.builder.SingleTestGenerator=/
com.example.MyGenerator

Using the Custom Stub Generator

如果您想要生成 WireMock 以外的存根服务器的存根,您可以插入您自己的 StubGenerator 接口实现。以下代码清单演示了 StubGenerator 接口:

If you want to generate stubs for stub servers other than WireMock, you can plug in your own implementation of the StubGenerator interface. The following code listing shows the StubGenerator interface:

Unresolved directive in pluggable-architecture.adoc - include::{converters_path}/src/main/java/org/springframework/cloud/contract/verifier/converter/StubGenerator.java[]

同样,您必须提供一个 spring.factories 文件,例如以下示例中所示:

Again, you must provide a spring.factories file, such as the one shown in the following example:

Unresolved directive in pluggable-architecture.adoc - include::{converters_path}/src/main/resources/META-INF/spring.factories[]

默认实现是 WireMock 存根生成。

The default implementation is the WireMock stub generation.

您可以提供多个存根生成器实现。例如,您可以从一个 DSL 生成 WireMock 存根和 Pact 文件。

You can provide multiple stub generator implementations. For example, from a single DSL, you can produce both WireMock stubs and Pact files.

Using the Custom Stub Runner

如果您决定使用自定义存根生成,您还需要一种使用您的不同存根提供商运行存根的自定义方式。

If you decide to use custom stub generation, you also need a custom way of running stubs with your different stub provider.

假设您使用 Moco构建存根,并且您编写了一个存根生成器并将存根放置在JAR文件中。

Assume that you use Moco to build your stubs and that you have written a stub generator and placed your stubs in a JAR file.

为了让存根运行器了解如何运行您的存根,您必须定义一个自定义 HTTP 存根服务器实现,它可能类似于以下示例:

In order for Stub Runner to know how to run your stubs, you have to define a custom HTTP Stub server implementation, which might resemble the following example:

Unresolved directive in pluggable-architecture.adoc - include::{tests_path}/spring-cloud-contract-stub-runner-moco/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/moco/MocoHttpServerStub.groovy[]

然后您可以在您的 spring.factories 文件中注册它,如下例所示:

Then you can register it in your spring.factories file, as the following example shows:

org.springframework.cloud.contract.stubrunner.HttpServerStub=\
org.springframework.cloud.contract.stubrunner.provider.moco.MocoHttpServerStub

现在,您可以使用 Moco 运行存根。

Now you can run stubs with Moco.

如果您不提供任何实现,则使用默认(WireMock)实现。如果您提供了多个,则使用列表中的第一个。

If you do not provide any implementation, the default (WireMock) implementation is used. If you provide more than one, the first one on the list is used.

Using the Custom Stub Downloader

您可以通过创建一个 StubDownloaderBuilder 接口的实现来自定义下载存根的方式,如下例所示:

You can customize the way your stubs are downloaded by creating an implementation of the StubDownloaderBuilder interface, as the following example shows:

package com.example;

class CustomStubDownloaderBuilder implements StubDownloaderBuilder {

	@Override
	public StubDownloader build(final StubRunnerOptions stubRunnerOptions) {
		return new StubDownloader() {
			@Override
			public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
					StubConfiguration config) {
				File unpackedStubs = retrieveStubs();
				return new AbstractMap.SimpleEntry<>(
						new StubConfiguration(config.getGroupId(), config.getArtifactId(), version,
								config.getClassifier()), unpackedStubs);
			}

			File retrieveStubs() {
			    // here goes your custom logic to provide a folder where all the stubs reside
			}
		}
	}
}

然后您可以在您的 spring.factories 文件中注册它,如下例所示:

Then you can register it in your spring.factories file, as the following example shows:

# Example of a custom Stub Downloader Provider
org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder=\
com.example.CustomStubDownloaderBuilder

现在您可以使用存根的源目录选择一个文件夹。

Now you can pick a folder with the source of your stubs.

如果您不提供任何实现,则使用默认(扫描类路径)。如果您提供 stubsMode = StubRunnerProperties.StubsMode.LOCALstubsMode = StubRunnerProperties.StubsMode.REMOTE,则使用 Aether 实现。如果您提供了多个,则使用列表中的第一个。

If you do not provide any implementation, the default (scanning the classpath) is used. If you provide the stubsMode = StubRunnerProperties.StubsMode.LOCAL or stubsMode = StubRunnerProperties.StubsMode.REMOTE, the Aether implementation is used If you provide more than one, the first one on the list is used.

Using the SCM Stub Downloader

每当 repositoryRoot 以 SCM 协议(当前,我们只支持 git://)开头时,存根下载器都会尝试克隆储存库,并将其用作产生测试或存根的合约的源。

Whenever the repositoryRoot starts with a SCM protocol (currently, we support only git://), the stub downloader tries to clone the repository and use it as a source of contracts to generate tests or stubs.

您可以通过环境变量、系统属性或在插件或合约储存库配置中设置的属性,修改下载器的行为。下表描述了可用的属性:

Through environment variables, system properties, or properties set inside the plugin or the contracts repository configuration, you can tweak the downloader’s behavior. The following table describes the available properties:

Table 1. SCM Stub Downloader properties

Type of a property

Name of the property

Description

* git.branch (plugin prop)

* stubrunner.properties.git.branch (system prop)

* STUBRUNNER_PROPERTIES_GIT_BRANCH (env prop)

master

Which branch to checkout

* git.username (plugin prop)

* stubrunner.properties.git.username (system prop)

* STUBRUNNER_PROPERTIES_GIT_USERNAME (env prop)

Git clone username

* git.password (plugin prop)

* stubrunner.properties.git.password (system prop)

* STUBRUNNER_PROPERTIES_GIT_PASSWORD (env prop)

Git clone password

* git.no-of-attempts (plugin prop)

* stubrunner.properties.git.no-of-attempts (system prop)

* STUBRUNNER_PROPERTIES_GIT_NO_OF_ATTEMPTS (env prop)

10

Number of attempts to push the commits to origin

* git.wait-between-attempts (Plugin prop)

* stubrunner.properties.git.wait-between-attempts (system prop)

* STUBRUNNER_PROPERTIES_GIT_WAIT_BETWEEN_ATTEMPTS (env prop)

1000

Number of milliseconds to wait between attempts to push the commits to origin