Maven 项目

添加 Maven 插件

要添加 Spring Cloud Contract BOM,请在文件中包含以下部分:pom.xmlspring-doc.cn

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

接下来,添加 Maven 插件,如下所示:Spring Cloud Contract Verifierspring-doc.cn

<plugin>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
	<version>${spring-cloud-contract.version}</version>
	<extensions>true</extensions>
	<configuration>
		<packageWithBaseClasses>com.example.fraud</packageWithBaseClasses>
	</configuration>
</plugin>

您可以在 spring-cloud-contract-maven-plugin/index.html[Spring] Cloud Contract Maven Plugin 文档]。spring-doc.cn

有时,无论选择哪种 IDE,您都可以看到该文件夹在 IDE 的类路径上不可见。为确保它始终存在,您可以将以下条目添加到target/generated-test-sourcepom.xmlspring-doc.cn

<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>build-helper-maven-plugin</artifactId>
	<executions>
		<execution>
			<id>add-source</id>
			<phase>generate-test-sources</phase>
			<goals>
				<goal>add-test-source</goal>
			</goals>
			<configuration>
				<sources>
					<source>${project.build.directory}/generated-test-sources/contracts/</source>
				</sources>
			</configuration>
		</execution>
	</executions>
</plugin>

Maven 和 Rest Assured 2.0

默认情况下,Rest Assured 3.x 将添加到 Classpath 中。但是,您可以使用 Rest 通过将 2.x 添加到 plugins 类路径来保证 2.x,如下所示:spring-doc.cn

<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <packageWithBaseClasses>com.example</packageWithBaseClasses>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-contract-verifier</artifactId>
            <version>${spring-cloud-contract.version}</version>
        </dependency>
        <dependency>
           <groupId>com.jayway.restassured</groupId>
           <artifactId>rest-assured</artifactId>
           <version>2.5.0</version>
           <scope>compile</scope>
        </dependency>
        <dependency>
           <groupId>com.jayway.restassured</groupId>
           <artifactId>spring-mock-mvc</artifactId>
           <version>2.5.0</version>
           <scope>compile</scope>
        </dependency>
    </dependencies>
</plugin>

<dependencies>
    <!-- all dependencies -->
    <!-- you can exclude rest-assured from spring-cloud-contract-verifier -->
    <dependency>
       <groupId>com.jayway.restassured</groupId>
       <artifactId>rest-assured</artifactId>
       <version>2.5.0</version>
       <scope>test</scope>
    </dependency>
    <dependency>
       <groupId>com.jayway.restassured</groupId>
       <artifactId>spring-mock-mvc</artifactId>
       <version>2.5.0</version>
       <scope>test</scope>
    </dependency>
</dependencies>

这样,插件会自动看到 Rest Assured 2.x 存在于 Classpath 中 并相应地修改导入。spring-doc.cn

使用 Maven 的快照版本和里程碑版本

要使用快照和里程碑版本,您必须将以下部分添加到您的 :pom.xmlspring-doc.cn

<repositories>
	<repository>
		<id>spring-snapshots</id>
		<name>Spring Snapshots</name>
		<url>https://repo.spring.io/snapshot</url>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
	</repository>
	<repository>
		<id>spring-milestones</id>
		<name>Spring Milestones</name>
		<url>https://repo.spring.io/milestone</url>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</repository>
</repositories>
<pluginRepositories>
	<pluginRepository>
		<id>spring-snapshots</id>
		<name>Spring Snapshots</name>
		<url>https://repo.spring.io/snapshot</url>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
	</pluginRepository>
	<pluginRepository>
		<id>spring-milestones</id>
		<name>Spring Milestones</name>
		<url>https://repo.spring.io/milestone</url>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</pluginRepository>
</pluginRepositories>

添加存根

默认情况下, Spring Cloud Contract Verifier 在目录中查找存根。包含存根定义的目录为 被视为类名,并且每个存根定义都被视为单个测试。我们假设 它至少包含一个要用作测试类名的目录。如果还有更多 而不是一个级别的嵌套目录,则除最后一个目录外的所有目录都用作包名称。 请考虑以下结构:src/test/resources/contractsspring-doc.cn

src/test/resources/contracts/myservice/shouldCreateUser.groovy
src/test/resources/contracts/myservice/shouldReturnUser.groovy

给定该结构,Spring Cloud Contract Verifier 创建一个测试类,该类使用两种方法命名:defaultBasePackage.MyServicespring-doc.cn

运行插件

插件目标被分配为在称为 .如果您希望它成为构建过程的一部分,则无需这样做 什么。如果只想生成测试,请调用 goal。generateTestsgenerate-test-sourcesgenerateTestsspring-doc.cn

如果要从 Maven 运行存根,请将包含存根的目标作为 system 属性调用,如下所示:runspring.cloud.contract.verifier.stubsspring-doc.cn

mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:run \ -Dspring.cloud.contract.verifier.stubs=“com.acme:服务名称”spring-doc.cn

配置插件

要更改默认配置,您可以向插件添加一个部分 定义或定义,如下所示:configurationexecutionspring-doc.cn

<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>convert</goal>
                <goal>generateStubs</goal>
                <goal>generateTests</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <basePackageForTests>org.springframework.cloud.verifier.twitter.place</basePackageForTests>
        <baseClassForTests>org.springframework.cloud.verifier.twitter.place.BaseMockMvcSpec</baseClassForTests>
    </configuration>
</plugin>

配置选项

  • testMode:定义验收测试的模式。默认情况下,模式为 , 它基于 Spring 的 MockMvc。您还可以将其更改为 、 或 (对于实际的 HTTP 调用)。MockMvcWebTestClientJaxRsClientExplicitspring-doc.cn

  • basePackageForTests:指定所有生成的测试的基础包。如果未设置,则 该值是从 和 from 的包中选取的。 如果这两个值均未设置,则该值将设置为 。baseClassForTestspackageWithBaseClassesorg.springframework.cloud.contract.verifier.testsspring-doc.cn

  • ruleClassForTests:指定应添加到生成的测试的规则 类。spring-doc.cn

  • baseClassForTests:为所有生成的测试创建一个基类。默认情况下,如果你 使用 Spock 类,则类为 。spock.lang.Specificationspring-doc.cn

  • contractsDirectory:指定一个目录,其中包含使用 Groovyn DSL.默认目录为 ./src/test/resources/contractsspring-doc.cn

  • generatedTestSourcesDir:指定生成测试的测试源目录 应该放置 Groovy DSL。默认情况下,其值为 。$buildDir/generated-test-sources/contractsspring-doc.cn

  • generatedTestResourcesDir:指定生成的测试使用的资源的测试资源目录。spring-doc.cn

  • testFramework:指定要使用的目标测试框架。目前,Spock、JUnit 4 () 和 支持 JUnit 5,其中 JUnit 4 是默认框架。TestFramework.JUNITspring-doc.cn

  • packageWithBaseClasses:定义所有基类所在的包。这 setting 优先于 。约定是这样的,如果你 在 (例如) 下有一个合约,并将 属性的值为 , Spring Cloud Contract Verifier 假定包下有一个类。换句话说,系统采用 package(如果存在)并形成一个 class 作为后缀。baseClassForTestssrc/test/resources/contract/foo/bar/baz/packageWithBaseClassescom.example.baseBarBazBasecom.example.baseBasespring-doc.cn

  • baseClassMappings:指定一个基类映射的列表,这些映射提供(根据协定所在的包进行检查 位于)和 ( 映射到 的基类的完全限定名称 匹配的合约)。例如,如果您在 AND Map 属性下有一个 CONTRACT,则从这些 CONTRACT 生成的 test 类 延伸。此设置优先于 和 。contractPackageRegexbaseClassFQNsrc/test/resources/contract/foo/bar/baz/.* → com.example.base.BaseClasscom.example.base.BaseClasspackageWithBaseClassesbaseClassForTestsspring-doc.cn

  • contractsProperties:包含要传递给 Spring Cloud Contract 的属性的 map 组件。这些属性可能由(例如)内置或自定义 Stub Downloader 使用。spring-doc.cn

  • failOnNoContracts:启用后,如果未找到 Contract,将引发异常。默认为 。truespring-doc.cn

  • failOnInProgress:如果设置为 ,则如果找到任何正在进行的合同,则它们会中断构建。在生产者方面,您需要明确说明您有正在进行的合同这一事实,并考虑到您可能会在消费者方面导致误报测试结果。默认为 。truetruespring-doc.cn

  • incrementalContractTests:启用后,仅当自上次构建以来合同发生更改时,才会创建测试。默认为 。truespring-doc.cn

  • incrementalContractStubs:启用后,仅当自上次构建以来合同发生更改时,才会创建存根。默认为 。truespring-doc.cn

  • incrementalContractStubsJar:启用后,仅当存根自上次构建以来发生更改时,才会创建存根 jar。默认为 。 * :提供存根的 WireMock 服务器的 HTTP 端口。目前,仅当从目录中提供存根时,property 才有效。否则,在提供存根 ID 时,必须在 id 字符串中包含 port。 *:将此项设置为可绕过验证程序执行。 *:将此项设置为绕过验证程序测试生成。 * : 要下载和运行的存根列表,以冒号分隔的 Ivy 表示法。 * :指定存根应从的最小端口开始。 * :指定存根应开始的最大端口。 * :指定插件在启动存根后是否应等待用户按下该键。 *:指定存根对象使用的分类器。truehttpPortspring.cloud.contract.verifier.http.portskiptrueskipTestOnlytruestubsminPortmaxPortwaitForKeyPressedstubsClassifierspring-doc.cn

如果要从 Maven 存储库下载合同定义,可以使用 以下选项:spring-doc.cn

  • contractDependency:包含所有打包合同的合同依赖项。spring-doc.cn

  • contractsPath:具有打包合同的 JAR 中具体合同的路径。 默认为 where is slash separated。groupid/artifactidgropuidspring-doc.cn

  • contractsMode:选择查找和注册存根的模式。spring-doc.cn

  • deleteStubsAfterTest:如果设置为 ,则不删除任何已下载的 来自临时目录的 Contract。falsespring-doc.cn

  • contractsRepositoryUrl:包含具有协定的构件的存储库的 URL。如果未提供, 使用当前的 Maven 的。spring-doc.cn

  • contractsRepositoryUsername:用于通过 Contract 连接到 repo 的用户名。spring-doc.cn

  • contractsRepositoryPassword:用于通过 Contract 连接到 repo 的密码。spring-doc.cn

  • contractsRepositoryProxyHost:用于通过 Contract 连接到 repo 的代理主机。spring-doc.cn

  • contractsRepositoryProxyPort:用于通过合约连接到仓库的代理端口。spring-doc.cn

我们只缓存非快照的、明确提供的版本(例如,或不缓存)。默认情况下,此功能处于打开状态。+1.0.0.BUILD-SNAPSHOTspring-doc.cn

以下列表描述了您可以在插件中打开的实验性功能:spring-doc.cn

  • convertToYaml:将所有 DSL 转换为声明式 YAML 格式。当您在 Groovy DSL 中使用外部库时,这可能非常有用。通过打开此功能(将其设置为 ),您无需在使用者端添加库依赖项。truespring-doc.cn

  • assertJsonSize:您可以在生成的测试中检查 JSON 数组的大小。默认情况下,此功能处于禁用状态。spring-doc.cn

所有测试的单个基类

在默认 () 中使用 Spring Cloud Contract Verifier 时,需要创建一个 base 规范。在此类中,您需要指向一个 endpoint,该端点应进行验证。以下示例显示了如何执行此操作:MockMvcspring-doc.cn

import org.mycompany.ExampleSpringController
import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc
import spock.lang.Specification

class MvcSpec extends Specification {
  def setup() {
   RestAssuredMockMvc.standaloneSetup(new ExampleSpringController())
  }
}

如有必要,您还可以设置整个上下文,如下例所示:spring-doc.cn

import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
public abstract class BaseTestClass {

	@Autowired
	WebApplicationContext context;

	@Before
	public void setup() {
		RestAssuredMockMvc.webAppContextSetup(this.context);
	}
}

如果使用 mode,则可以使用基类来初始化整个测试的应用程序。 类似于您在常规集成测试中可能执行的操作。以下示例显示了 如何操作:EXPLICITspring-doc.cn

import io.restassured.RestAssured;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
public abstract class BaseTestClass {

	@LocalServerPort
	int port;

	@Before
	public void setup() {
		RestAssured.baseURI = "http://localhost:" + this.port;
	}
}

如果使用 mode,则此基类还应包含一个字段。右 现在,测试 JAX-RS API 的唯一方法是启动 Web 服务器。JAXRSCLIENTprotected WebTarget webTargetspring-doc.cn

对 Contract 使用不同的基类

如果您的基类在 Contract 之间不同,则可以告诉 Spring Cloud Contract plugin 哪个类应该由自动生成的测试进行扩展。您有两个选项:spring-doc.cn

按约定

约定是这样的,如果您在(例如)下有一个 Contract 并将属性的值设置为,则 Spring Cloud Contract 验证程序假定包下有一个类。 换句话说,系统采用包的最后两部分(如果存在),并且 形成一个带有后缀的类。此规则优先于 。 以下示例显示了它在闭包中的工作原理:src/test/resources/contract/foo/bar/baz/packageWithBaseClassescom.example.baseBarBazBasecom.example.baseBasebaseClassForTestscontractsspring-doc.cn

<plugin>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
	<configuration>
		<packageWithBaseClasses>hello</packageWithBaseClasses>
	</configuration>
</plugin>

按映射

您可以手动将 Contract 包的正则表达式映射到完全限定的 匹配合约的基类名称。您必须提供一个 name,该列表由每个对象组成,每个对象都采用 to 映射。请考虑以下示例:baseClassMappingsbaseClassMappingcontractPackageRegexbaseClassFQNspring-doc.cn

<plugin>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
	<configuration>
		<baseClassForTests>com.example.FooBase</baseClassForTests>
		<baseClassMappings>
			<baseClassMapping>
				<contractPackageRegex>.*com.*</contractPackageRegex>
				<baseClassFQN>com.example.TestBase</baseClassFQN>
			</baseClassMapping>
		</baseClassMappings>
	</configuration>
</plugin>

假设您在以下两个位置签订了合同:spring-doc.cn

通过提供 ,我们可以在映射未成功的情况下进行回退。 (您还可以提供 作为后备。这样,测试 从 Contract 生成 扩展 ,而其余测试扩展 。baseClassForTestspackageWithBaseClassessrc/test/resources/contract/com/com.example.ComBasecom.example.FooBasespring-doc.cn

调用生成的测试

Spring Cloud Contract Maven Plugin 在名为 goal 的目录中生成验证码,并将该目录附加到 goal。/generated-test-sources/contractVerifiertestCompilespring-doc.cn

对于 Groovy Spock 代码,您可以使用以下内容:spring-doc.cn

<plugin>
	<groupId>org.codehaus.gmavenplus</groupId>
	<artifactId>gmavenplus-plugin</artifactId>
	<version>1.5</version>
	<executions>
		<execution>
			<goals>
				<goal>testCompile</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<testSources>
			<testSource>
				<directory>${project.basedir}/src/test/groovy</directory>
				<includes>
					<include>**/*.groovy</include>
				</includes>
			</testSource>
			<testSource>
				<directory>${project.build.directory}/generated-test-sources/contractVerifier</directory>
				<includes>
					<include>**/*.groovy</include>
				</includes>
			</testSource>
		</testSources>
	</configuration>
</plugin>

要确保提供者端符合定义的 Contract,您需要调用 .mvn generateTest testspring-doc.cn

将存根推送到 SCM

如果您使用 SCM (Source Control Management) 存储库来保存合同和 stubs 中,您可能希望自动执行将 stub 推送到 存储库。为此,您可以添加目标。以下示例显示了如何执行此操作:pushStubsToScmspring-doc.cn

<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <!-- Base class mappings etc. -->

        <!-- We want to pick contracts from a Git repository -->
        <contractsRepositoryUrl>git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git</contractsRepositoryUrl>

        <!-- We reuse the contract dependency section to set up the path
        to the folder that contains the contract definitions. In our case the
        path will be /groupId/artifactId/version/contracts -->
        <contractDependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>${project.artifactId}</artifactId>
            <version>${project.version}</version>
        </contractDependency>

        <!-- The contracts mode can't be classpath -->
        <contractsMode>REMOTE</contractsMode>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <!-- By default we will not push the stubs back to SCM,
                you have to explicitly add it as a goal -->
                <goal>pushStubsToScm</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Using the SCM Stub Downloader 下,您可以找到所有可能的 您可以传递的配置选项 map 的 system 属性 或环境变量。例如,您可以指定要签出的具体分支,而不是默认分支<configuration><contractsProperties>spring-doc.cn

<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <!-- Base class mappings etc. -->

        <!-- We want to pick contracts from a Git repository -->
        <contractsRepositoryUrl>git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git</contractsRepositoryUrl>
	<contractsProperties>
            <git.branch>another_branch</git.branch>
        </contractsProperties>

        <!-- We reuse the contract dependency section to set up the path
        to the folder that contains the contract definitions. In our case the
        path will be /groupId/artifactId/version/contracts -->
        <contractDependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>${project.artifactId}</artifactId>
            <version>${project.version}</version>
        </contractDependency>

        <!-- The contracts mode can't be classpath -->
        <contractsMode>REMOTE</contractsMode>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <!-- By default we will not push the stubs back to SCM,
                you have to explicitly add it as a goal -->
                <goal>pushStubsToScm</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Maven 插件和 STS

下图显示了在使用 STS 时可能会看到的异常:spring-doc.cn

STS 异常

当您单击错误标记时,您应该会看到如下所示的内容:spring-doc.cn

 plugin:1.1.0.M1:convert:default-convert:process-test-resources) org.apache.maven.plugin.PluginExecutionException: Execution default-convert of goal org.springframework.cloud:spring-
 cloud-contract-maven-plugin:1.1.0.M1:convert failed. at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:145) at
 org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:331) at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1362) at
...
 org.eclipse.core.internal.jobs.Worker.run(Worker.java:55) Caused by: java.lang.NullPointerException at
 org.eclipse.m2e.core.internal.builder.plexusbuildapi.EclipseIncrementalBuildContext.hasDelta(EclipseIncrementalBuildContext.java:53) at
 org.sonatype.plexus.build.incremental.ThreadBuildContext.hasDelta(ThreadBuildContext.java:59) at

要解决此问题,请在 :pom.xmlspring-doc.cn

<build>
    <pluginManagement>
        <plugins>
            <!--This plugin's configuration is used to store Eclipse m2e settings
                only. It has no influence on the Maven build itself. -->
            <plugin>
                <groupId>org.eclipse.m2e</groupId>
                <artifactId>lifecycle-mapping</artifactId>
                <version>1.0.0</version>
                <configuration>
                    <lifecycleMappingMetadata>
                        <pluginExecutions>
                             <pluginExecution>
                                <pluginExecutionFilter>
                                    <groupId>org.springframework.cloud</groupId>
                                    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
                                    <versionRange>[1.0,)</versionRange>
                                    <goals>
                                        <goal>convert</goal>
                                    </goals>
                                </pluginExecutionFilter>
                                <action>
                                    <execute />
                                </action>
                             </pluginExecution>
                        </pluginExecutions>
                    </lifecycleMappingMetadata>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

带有 Spock 测试的 Maven 插件

您可以选择 Spock Framework 来创建和运行自动生成的合约 使用 Maven 和 Gradle 进行验证测试。但是,虽然使用 Gradle 很简单, 在 Maven 中,您需要一些额外的设置才能使测试正确编译和执行。spring-doc.cn

首先,您必须使用插件,例如 GMavenPlus 插件, 将 Groovy 添加到您的项目中。在 GMavenPlus 插件中,您需要显式设置测试源,包括 path 来定义您的基本测试类,并且 path 是添加生成的 Contract 测试的。 以下示例说明如何执行此操作。spring-doc.cn

如果您坚持 Spock 约定,即以 结束测试类名,则还需要调整您的 Maven Surefire 插件设置,如下所示。Specspring-doc.cn