Gradle 项目
先决条件
要使用 Spring Cloud Contract Verifier 与 WireMock,你必须使用 Gradle 或 Maven 插件。
如果你想在项目中使用 Spock,必须单独添加 spock-core 和 spock-spring 模块。更多信息请参阅 Spock 的文档。
添加 Gradle 插件与依赖
要添加带有依赖项的 Gradle 插件,你可以使用类似以下的代码:
插件 DSL GA 版本
// build.gradle
plugins {
id "groovy"
// this will work only for GA versions of Spring Cloud Contract
id "org.springframework.cloud.contract" version "$\{GAVerifierVersion}"
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:$\{GAVerifierVersion}"
}
}
dependencies {
testImplementation "org.apache.groovy:groovy-all:$\{groovyVersion}"
// example with adding Spock core and Spock Spring
testImplementation "org.spockframework:spock-core:$\{spockVersion}"
testImplementation "org.spockframework:spock-spring:$\{spockVersion}"
testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
}
插件 DSL 非正式发布版本
// settings.gradle
pluginManagement {
plugins {
id "org.springframework.cloud.contract" version "$\{verifierVersion}"
}
repositories {
// to pick from local .m2
mavenLocal()
// for snapshots
maven { url "https://repo.spring.io/snapshot" }
// for milestones
maven { url "https://repo.spring.io/milestone" }
// for GA versions
gradlePluginPortal()
}
}
// build.gradle
plugins {
id "groovy"
id "org.springframework.cloud.contract"
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:$\{verifierVersion}"
}
}
dependencies {
testImplementation "org.apache.groovy:groovy-all:$\{groovyVersion}"
// example with adding Spock core and Spock Spring
testImplementation "org.spockframework:spock-core:$\{spockVersion}"
testImplementation "org.spockframework:spock-spring:$\{spockVersion}"
testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
}
Legacy Plugin Application
// build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:$\{springboot_version}"
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:$\{verifier_version}"
// here you can also pass additional dependencies such as Kotlin spec e.g.:
// classpath "org.springframework.cloud:spring-cloud-contract-spec-kotlin:$\{verifier_version}"
}
}
apply plugin: 'groovy'
apply plugin: 'org.springframework.cloud.contract'
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:$\{verifier_version}"
}
}
dependencies {
testImplementation "org.apache.groovy:groovy-all:$\{groovyVersion}"
// example with adding Spock core and Spock Spring
testImplementation "org.spockframework:spock-core:$\{spockVersion}"
testImplementation "org.spockframework:spock-spring:$\{spockVersion}"
testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
}
Gradle 与 Rest Assured 2.0
默认情况下,Rest Assured 3.x 已添加到类路径中。但是,要使用 Rest Assured 2.x,你可以改为添加它,如下所示:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:$\{springboot_version}"
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:$\{verifier_version}"
}
}
dependencies {
// all dependencies
// you can exclude rest-assured from spring-cloud-contract-verifier
testCompile "com.jayway.restassured:rest-assured:2.5.0"
testCompile "com.jayway.restassured:spring-mock-mvc:2.5.0"
}
这样,插件会自动检测到类路径上存在 Rest Assured 2.x,并相应地修改导入语句。
Gradle 的快照版本
您可以将额外的快照仓库添加到 settings.gradle 中,以使用快照版本,这些版本会在每次成功构建后自动上传。
添加存根
默认情况下,Spring Cloud Contract Verifier 会在 src/contractTest/resources/contracts 目录中查找存根。出于过渡目的,插件也会在 src/test/resources/contracts 目录中查找契约,但从 Spring Cloud Contract 3.0.0 开始,此目录已被弃用。
同样需要注意的是,对于这个新的 Gradle 源集,您还应该将契约测试中使用的任何基类迁移到 src/contractTest/{language} 目录下,其中 {language} 应根据您的需要替换为 Java 或 Groovy。
包含存根定义的目录被视为类名,每个存根定义被视为单个测试。Spring Cloud Contract Verifier 假定它至少包含一个目录层级,该层级将被用作测试类名。如果存在多个嵌套目录层级,则除最后一个层级外的所有层级都将用作包名。考虑以下结构:
src/contractTest/resources/contracts/myservice/shouldCreateUser.groovy
src/contractTest/resources/contracts/myservice/shouldReturnUser.groovy
根据上述结构,Spring Cloud Contract Verifier 会创建一个名为 defaultBasePackage.MyService 的测试类,其中包含两个方法:
-
shouldCreateUser() -
shouldReturnUser()
运行插件
该插件会在 check 任务之前自动注册并执行。若希望将其纳入构建流程,无需额外操作。若仅需生成测试,请调用 generateContractTests 任务。
默认设置
默认的 Gradle 插件设置会创建以下构建的 Gradle 部分(伪代码):
contracts {
testFramework ='JUNIT'
testMode = 'MockMvc'
generatedTestJavaSourcesDir = project.file("$\{project.buildDir}/generated-test-sources/contractTest/java")
generatedTestGroovySourcesDir = project.file("$\{project.buildDir}/generated-test-sources/contractTest/groovy")
generatedTestResourcesDir = project.file("$\{project.buildDir}/generated-test-resources/contracts")
contractsDslDir = project.file("$\{project.projectDir}/src/contractTest/resources/contracts")
basePackageForTests = 'org.springframework.cloud.verifier.tests'
stubsOutputDir = project.file("$\{project.buildDir}/stubs")
sourceSet = null
}
def verifierStubsJar = tasks.register(type: Jar, name: 'verifierStubsJar', dependsOn: 'generateClientStubs') {
baseName = project.name
classifier = contracts.stubsSuffix
from contractVerifier.stubsOutputDir
}
def copyContracts = tasks.register(type: Copy, name: 'copyContracts') {
from contracts.contractsDslDir
into contracts.stubsOutputDir
}
verifierStubsJar.dependsOn copyContracts
配置插件
要更改默认配置,您可以在 Gradle 配置中添加一个 contracts 代码片段,如下所示:
contracts {
testMode = 'MockMvc'
baseClassForTests = 'org.mycompany.tests'
generatedTestJavaSourcesDir = project.file('src/generatedContract')
}
要从远程源下载合约,你可以根据需要参考以下代码片段:
contracts {
// If your contracts exist in a JAR archive published to a Maven repository
contractDependency {
stringNotation = ''
// OR
groupId = ''
artifactId = ''
version = ''
classifier = ''
}
// If your contracts exist in a Git SCM repository
contractRepository {
repositoryUrl = ''
// username = ''
// password = ''
}
// controls the nested location to find the contracts in either the JAR or Git SCM source
contractsPath = ''
}
由于我们使用的是 Gradle 的 Jar 打包任务,您可能希望利用一些选项和功能来进一步扩展 verifierStubsJar 所创建的内容。为此,您可以直接使用 Gradle 提供的原生机制来定制现有任务,具体操作如下:
为了示例起见,我们希望将 git.properties 文件添加到 verifierStubsJar 中。
verifierStubsJar {
from("$\{buildDir}/resources/main/") {
include("git.properties")
}
}
还需注意的是,自3.0.0版本起,默认的发布功能已被禁用。这意味着,您能够创建任意命名的jar文件,并通过Gradle配置选项像往常一样发布它。也就是说,您可以构建一个完全按照您意愿定制的jar文件,并发布它,从而实现对jar文件布局和内容的绝对控制。
配置选项
-
testMode:定义验收测试的模式。默认模式为 MockMvc,它基于 Spring 的 MockMvc。也可以更改为 WebTestClient、JaxRsClient 或 Explicit(用于真实的 HTTP 调用)。 -
imports:创建一个数组,包含应包含在生成的测试中的导入(例如['org.myorg.Matchers'])。默认情况下,它创建一个空数组。 -
staticImports:创建一个数组,包含应包含在生成的测试中的静态导入(例如['org.myorg.Matchers.*'])。默认情况下,它创建一个空数组。 -
basePackageForTests:指定所有生成测试的基础包。如果未设置,则从baseClassForTests的包和packageWithBaseClasses中选取值。如果这两个值都未设置,则值设置为org.springframework.cloud.contract.verifier.tests。 -
baseClassForTests:为所有生成的测试创建一个基类。默认情况下,如果使用 Spock 类,则类为spock.lang.Specification。 -
packageWithBaseClasses:定义所有基类所在的包。此设置优先于baseClassForTests。 -
baseClassMappings:显式地将合约包映射到基类的完全限定名。此设置优先于packageWithBaseClasses和baseClassForTests。 -
ignoredFiles:使用Antmatcher允许定义应跳过处理的存根文件。默认情况下,它是一个空数组。 -
contractsDslDir:指定包含使用 GroovyDSL 编写的合约的目录。默认情况下,其值为$projectDir/src/contractTest/resources/contracts。 -
generatedTestSourcesDir:指定测试源目录,其中应放置从 Groovy DSL 生成的测试。(已弃用) -
generatedTestJavaSourcesDir:指定测试源目录,其中应放置从 Groovy DSL 生成的 Java/JUnit 测试。默认情况下,其值为$buildDir/generated-tes-sources/contractTest/java。 -
generatedTestGroovySourcesDir:指定测试源目录,其中应放置从 Groovy DSL 生成的 Groovy/Spock 测试。默认情况下,其值为$buildDir/generated-test-sources/contractTest/groovy。 -
generatedTestResourcesDir:指定测试资源目录,其中应放置由从 Groovy DSL 生成的测试使用的资源。默认情况下,其值为$buildDir/generated-test-resources/contractTest。 -
stubsOutputDir:指定应放置从 Groovy DSL 生成的 WireMock 存根的目录。 -
testFramework:指定要使用的目标测试框架。目前支持 Spock、JUnit 4(TestFramework.JUNIT)和 JUnit 5,其中 JUnit 4 是默认框架。 -
contractsProperties:一个包含要传递给 Spring Cloud Contract 组件的属性的映射。这些属性可能被(例如)内置或自定义的 Stub Downloader 使用。 -
sourceSet:存储合约的源集。如果未提供,则假定为contractTest(例如,对于 JUnit 为project.sourceSets.contractTest.java,对于 Spock 为project.sourceSets.contractTest.groovy)。
当您需要指定包含合约的JAR文件位置时,可以使用以下属性:
-
contractDependency: 指定提供groupid:artifactid:version:classifier坐标的依赖项。您可以使用contractDependency闭包来设置它。 -
contractsPath: 指定 jar 文件的路径。如果合约依赖项已下载,则路径默认为groupid/artifactid,其中groupid以斜杠分隔。否则,它将在提供的目录下扫描合约。 -
contractsMode: 指定下载合约的模式(JAR 是否离线可用、远程可用等)。 -
deleteStubsAfterTest: 如果设置为false,则不会从临时目录中删除任何已下载的合约。 -
failOnNoContracts: 启用后,当未找到任何合约时将抛出异常。默认为true。 -
failOnInProgress: 如果设置为true,那么如果发现任何进行中的合约,它们将中断构建。在生产者端,您需要明确说明您有进行中的合约,并考虑到您可能在消费者端导致误报的测试结果。默认为true。
此外,还有 contractRepository { … } 闭包,它包含以下属性
-
repositoryUrl:包含合约定义代码库的 URL -
username:代码库用户名 -
password:代码库密码 -
proxyPort:代理端口 -
proxyHost:代理主机 -
cacheDownloadedContracts:如果设置为true,将缓存下载非快照合约工件的文件夹。默认为true。
你也可以在插件中开启以下实验性功能:
-
convertToYaml: 将所有 DSL 转换为声明式的 YAML 格式。当你在 Groovy DSL 中使用外部库时,这可能会非常有用。通过启用此功能(将其设置为true),你无需在使用方添加库依赖。 -
assertJsonSize: 你可以检查生成测试中 JSON 数组的大小。此功能默认处于禁用状态。
所有测试的单一基类
在使用 MockMvc(默认方式)的 Spring Cloud Contract Verifier 时,你需要为所有生成的验收测试创建一个基础规范。在这个类中,你需要指向一个待验证的端点。以下示例展示了如何实现:
abstract class BaseMockMvcSpec extends Specification {
def setup() {
RestAssuredMockMvc.standaloneSetup(new PairIdController())
}
void isProperCorrelationId(Integer correlationId) {
assert correlationId == 123456
}
void isEmpty(String value) {
assert value == null
}
}
如果你使用 Explicit 模式,你可以使用一个基类来初始化整个被测试的应用程序,就像你在常规集成测试中看到的那样。如果你使用 JAXRSCLIENT 模式,这个基类还应包含一个 protected WebTarget webTarget 字段。目前,测试 JAX-RS API 的唯一方法是启动一个 Web 服务器。
合约的不同基类
如果您的合约之间的基类不同,您可以告诉 Spring Cloud Contract 插件应该由自动生成的测试扩展哪个类。您有两种选择:
-
遵循约定,提供
packageWithBaseClasses -
通过使用
baseClassMappings提供显式映射
按约定
按照惯例,如果你在(例如)src/contractTest/resources/contract/foo/bar/baz/ 目录下有一个合约,并将 packageWithBaseClasses 属性的值设置为 com.example.base,那么 Spring Cloud Contract Verifier 会假设在 com.example.base 包下存在一个 BarBazBase 类。换句话说,系统会取包名的最后两部分(如果存在),并形成一个带有 Base 后缀的类。此规则优先于 baseClassForTests。
通过映射
你可以手动将合约包的正则表达式映射到匹配合约的基类的完全限定名。你需要提供一个名为 baseClassMappings 的列表,该列表由 baseClassMapping 对象组成,这些对象包含从 contractPackageRegex 到 baseClassFQN 的映射。
假设您在以下目录中有合约:
-
src/contractTest/resources/contract/com/ -
src/contractTest/resources/contract/foo/
通过提供 baseClassForTests,我们可以在映射失败时有一个备用方案。(你也可以将 packageWithBaseClasses 作为备用方案。)这样,从 src/contractTest/resources/contract/com/ 合约生成的测试将继承 com.example.ComBase,而其余测试则继承 com.example.FooBase。
调用生成的测试
为确保提供方符合您定义的契约,您需要运行以下命令:
./gradlew contractTest
发布存根到制品仓库
如果你使用二进制制品仓库来存储存根,你需要为 Gradle 配置发布部分以包含 verifierStubsJar。为此,你可以使用以下示例配置:
apply plugin: 'maven-publish'
publishing {
publications {
maven(MavenPublication) {
// other configuration
artifact verifierStubsJar
}
}
}
自 3.0.0 版本起,内部存根发布功能已被弃用,并默认禁用。建议将 verifierStubsJar 包含在您自己的发布中。
推送存根到 SCM
如果你使用SCM仓库来存储合约和存根,你可能希望自动化将存根推送到仓库的步骤。为此,你可以通过运行以下命令来调用 pushStubsToScm 任务:
$ ./gradlew pushStubsToScm
在使用SCM存根下载器下,您可以找到所有可能的配置选项,这些选项可以通过 contractsProperties 字段(例如 contracts { contractsProperties = [foo:"bar"] })、通过 contractsProperties 方法(例如 contracts { contractsProperties([foo:"bar"]) }),或者通过系统属性或环境变量来传递。
消费者端的 Spring Cloud Contract Verifier
在消费方服务中,你需要以与提供方完全相同的方式配置 Spring Cloud Contract Verifier 插件。如果你不想使用 Stub Runner,则需要复制存储在 src/contractTest/resources/contracts 中的契约,并使用以下命令生成 WireMock JSON 存根:
./gradlew generateClientStubs
必须设置 stubsOutputDir 选项才能使存根生成功能正常工作。
当存在时,你可以在自动化测试中使用 JSON 存根来消费服务。以下示例展示了如何操作:
@ContextConfiguration(loader == SpringApplicationContextLoader, classes == Application)
class LoanApplicationServiceSpec extends Specification {
@ClassRule
@Shared
WireMockClassRule wireMockRule == new WireMockClassRule()
@Autowired
LoanApplicationService sut
def 'should successfully apply for loan'() {
given:
LoanApplication application =
new LoanApplication(client: new Client(clientPesel: '12345678901'), amount: 123.123)
when:
LoanApplicationResult loanApplication == sut.loanApplication(application)
then:
loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLIED
loanApplication.rejectionReason == null
}
}
在前面的示例中,LoanApplication 向 FraudDetection 服务发起了一次调用。该请求由一个 WireMock 服务器处理,该服务器配置了由 Spring Cloud Contract Verifier 生成的存根。