Gradle プロジェクト

前提条件

Spring Cloud Contract Verifier を WireMock で使用するには、Gradle または Maven プラグインを使用する必要があります。

プロジェクトで Spock を使用する場合は、spock-core モジュールと spock-spring モジュールを個別に追加する必要があります。詳細については、"Spock のドキュメント (英語) " を参照してください。

依存関係のある Gradle プラグインを追加する

依存関係のある Gradle プラグインを追加するには、次のようなコードを使用できます。

  • プラグイン DSL GA バージョン

  • プラグイン 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'
}
// 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'
}
// 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 と安心の 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 に追加して、次のように、ビルドが成功するたびに自動的にアップロードされるスナップショットバージョンを使用できます。

pluginManagement {
    repositories {
        mavenLocal()
        maven { url "https://repo.spring.io/snapshot" }
        maven { url "https://repo.spring.io/milestone" }
        gradlePluginPortal()
    }
}

スタブの追加

デフォルトでは、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 は、テストクラス名として使用されるディレクトリの少なくとも 1 レベルが含まれていることを前提としています。複数のレベルのネストされたディレクトリが存在する場合、最後のディレクトリを除くすべてがパッケージ名として使用されます。次の構造を考えてみましょう。

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

前述の構造を考慮すると、Spring Cloud Contract Verifier は 2 つのメソッドを使用して 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

プラグインの設定

デフォルト構成を変更するには、次のように、contracts スニペットを Gradle 構成に追加します。

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 以降、デフォルトのパブリケーションが無効になっていることにも注意してください。結果として、これは、Gradle 構成オプションを使用して通常行うのと同じように、任意の名前付き jar を作成し、公開できることを意味します。これは、希望どおりにカスタマイズした 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: 契約 パッケージを基本クラスの FQN に明示的にマップします。この設定は packageWithBaseClasses および baseClassForTests よりも優先されます。

  • ignoredFilesAntmatcher を使用して、処理をスキップするスタブファイルを定義できるようにします。デフォルトでは、空の配列です。

  • 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 コンポーネントに渡されるプロパティを含むマップ。これらのプロパティは、(たとえば) 組み込みまたはカスタムのスタブダウンローダーによって使用される可能性があります。

  • sourceSet: 契約が保存されるソースセット。指定しない場合は、contractTest とみなされます (たとえば、JUnit の場合は project.sourceSets.contractTest.java、Spock の場合は project.sourceSets.contractTest.groovy )。

契約を含む JAR の場所を指定する場合は、次のプロパティを使用できます。

  • contractDependencygroupid:artifactid:version:classifier 座標を提供する依存関係を指定します。contractDependency クロージャーを使用してセットアップできます。

  • contractsPath: jar へのパスを指定します。契約の依存関係がダウンロードされる場合、パスはデフォルトで groupid/artifactid になり、groupid はスラッシュで区切られます。それ以外の場合は、指定されたディレクトリにある契約をスキャンします。

  • contractsMode: 契約をダウンロードするモード (JAR がオフライン、リモートなどで利用可能かどうか) を指定します。

  • deleteStubsAfterTestfalse に設定すると、ダウンロードされた契約は一時ディレクトリから削除されません。

  • failOnNoContracts: 有効にすると、契約が見つからなかった場合に例外がスローされます。デフォルトは true です。

  • failOnInProgresstrue に設定すると、進行中の契約が見つかると、ビルドが中断されます。プロデューサー側では、進行中の契約があるという事実を明確にし、コンシューマー側で偽陽性の検査結果が生じる可能性があることを考慮する必要があります。デフォルトは 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 プラグインに指示できます。次の 2 つのオプションがあります。

  • packageWithBaseClasses を提供することで慣例に従います

  • baseClassMappings を使用して明示的なマッピングを提供する

慣例により

この規則では、(たとえば) src/contractTest/resources/contract/foo/bar/baz/ に契約があり、packageWithBaseClasses プロパティの値を com.example.base に設定した場合、Spring Cloud Contract Verifier は com.example.base パッケージに BarBazBase クラスがあると想定します。つまり、システムはパッケージの最後の 2 つの部分 (存在する場合) を取得し、Base サフィックスを持つクラスを形成します。このルールは baseClassForTests よりも優先されます。

マッピングによる

契約のパッケージの正規表現を、一致する契約の基本クラスの完全修飾名に手動でマップできます。contractPackageRegex から baseClassFQN へのマッピングを取る baseClassMapping オブジェクトで構成される baseClassMappings というリストを提供する必要があります。

次のディレクトリに契約があると仮定します。

  • 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

アーティファクトリポジトリへのスタブの公開

バイナリアーティファクトリポジトリを使用してスタブを保持する場合は、verifierStubsJar を含めるように Gradle の公開セクションを構成する必要があります。これを行うには、以下の構成例を使用できます。

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 検証者

消費側サービスでは、プロバイダーの場合とまったく同じ方法で Spring Cloud Contract Verifier プラグインを構成する必要があります。スタブランナーを使用したくない場合は、次のコマンドを使用して、src/contractTest/resources/contracts に保存されている契約をコピーし、WireMock JSON スタブを生成する必要があります。

./gradlew generateClientStubs
スタブ生成が機能するには、stubsOutputDir オプションを設定する必要があります。

JSON スタブが存在する場合、自動テストで 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 サービスを呼び出します。このリクエストは、Spring Cloud Contract Verifier によって生成されたスタブで構成された WireMock サーバーによって処理されます。