1. 序章

Spring Cloud Contract は、簡単に言えば、 Consumer-Driven Contracts(CDC)の作成に役立つプロジェクトです。

これにより、分散システムでのProducerConsumerの間の契約が、HTTPベースとメッセージベースの両方の対話で保証されます。

この簡単な記事では、HTTPインタラクションを介したSpringCloudContractのプロデューサー側とコンシューマー側のテストケースの作成について説明します。

2. プロデューサー–サーバー側

EvenOddController の形式でプロデューサー側のCDCを記述します。これは、numberパラメーターが偶数か奇数かを示すだけです。

@RestController
public class EvenOddController {

    @GetMapping("/validate/prime-number")
    public String isNumberPrime(@RequestParam("number") Integer number) {
        return Integer.parseInt(number) % 2 == 0 ? "Even" : "Odd";
    }
}

2.1. Mavenの依存関係

プロデューサー側では、spring-cloud-starter-contract-verifier依存関係が必要です。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-contract-verifier</artifactId>
    <version>2.1.1.RELEASE</version>
    <scope>test</scope>
</dependency>

そして、次のセクションで説明する基本テストクラスの名前でspring-cloud-contract-maven-pluginを構成する必要があります。

<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>2.1.1.RELEASE</version>
    <extensions>true</extensions>
    <configuration>
        <baseClassForTests>
            com.baeldung.spring.cloud.springcloudcontractproducer.BaseTestClass
        </baseClassForTests>
    </configuration>
</plugin>

2.2. プロデューサー側のセットアップ

Springコンテキストをロードする基本クラスをテストパッケージに追加する必要があります。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@DirtiesContext
@AutoConfigureMessageVerifier
public class BaseTestClass {

    @Autowired
    private EvenOddController evenOddController;

    @Before
    public void setup() {
        StandaloneMockMvcBuilder standaloneMockMvcBuilder 
          = MockMvcBuilders.standaloneSetup(evenOddController);
        RestAssuredMockMvc.standaloneSetup(standaloneMockMvcBuilder);
    }
}

/ src / test / resources / Contracts /パッケージで、次のようなテストスタブをファイルshouldReturnEvenWhenRequestParamIsEven.groovyに追加します。

import org.springframework.cloud.contract.spec.Contract
Contract.make {
    description "should return even when number input is even"
    request{
        method GET()
        url("/validate/prime-number") {
            queryParameters {
                parameter("number", "2")
            }
        }
    }
    response {
        body("Even")
        status 200
    }
}

ビルドを実行すると、プラグインは、BaseTestClassを拡張するContractVerifierTestという名前のテストクラスを自動的に生成し、 / target /generated-test-sources / Contracts/に配置します。

テストメソッドの名前は、Groovyテストスタブの名前と連結されたプレフィックス「 validate_」から派生しています。 上記のGroovyファイルの場合、生成されるメソッド名は「validate_shouldReturnEvenWhenRequestParamIsEven」になります。

この自動生成されたテストクラスを見てみましょう。

public class ContractVerifierTest extends BaseTestClass {

@Test
public void validate_shouldReturnEvenWhenRequestParamIsEven() throws Exception {
    // given:
    MockMvcRequestSpecification request = given();

    // when:
    ResponseOptions response = given().spec(request)
      .queryParam("number","2")
      .get("/validate/prime-number");

    // then:
    assertThat(response.statusCode()).isEqualTo(200);
    
    // and:
    String responseBody = response.getBody().asString();
    assertThat(responseBody).isEqualTo("Even");
}

ビルドは、ローカルのMavenリポジトリにスタブjarも追加して、コンシューマーが使用できるようにします。

スタブは、 stubs / mapping/の下の出力フォルダーにあります。

3. 消費者–クライアント側

CDCのコンシューマー側は、HTTPインタラクションを介してプロデューサー側によって生成されたスタブを消費してコントラクトを維持するため、プロデューサー側で変更を加えるとコントラクトが破られます

BasicMathController、を追加します。これにより、生成されたスタブから応答を取得するためのHTTPリクエストが作成されます。

@RestController
public class BasicMathController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/calculate")
    public String checkOddAndEven(@RequestParam("number") Integer number) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Content-Type", "application/json");

        ResponseEntity<String> responseEntity = restTemplate.exchange(
          "http://localhost:8090/validate/prime-number?number=" + number,
          HttpMethod.GET,
          new HttpEntity<>(httpHeaders),
          String.class);

        return responseEntity.getBody();
    }
}

3.1. Mavenの依存関係

コンシューマーの場合、spring-cloud-contract-wiremockおよびspring-cloud-contract-stub-runnerの依存関係を追加する必要があります。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-wiremock</artifactId>
    <version>2.1.1.RELEASE</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-stub-runner</artifactId>
    <version>2.1.1.RELEASE</version>
    <scope>test</scope>
</dependency>

3.2. 消費者側のセットアップ

次に、スタブランナーを構成します。これにより、ローカルのMavenリポジトリで使用可能なスタブがコンシューマーに通知されます。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
@AutoConfigureJsonTesters
@AutoConfigureStubRunner(
  stubsMode = StubRunnerProperties.StubsMode.LOCAL,
  ids = "com.baeldung.spring.cloud:spring-cloud-contract-producer:+:stubs:8090")
public class BasicMathControllerIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void given_WhenPassEvenNumberInQueryParam_ThenReturnEven()
      throws Exception {
 
        mockMvc.perform(MockMvcRequestBuilders.get("/calculate?number=2")
          .contentType(MediaType.APPLICATION_JSON))
          .andExpect(status().isOk())
          .andExpect(content().string("Even"));
    }
}

@AutoConfigureStubRunnerアノテーションのidsプロパティは次のことを指定していることに注意してください。

  • com.baeldung.spring.cloud —アーティファクトの groupId
  • spring-cloud-contract-producer —プロデューサースタブjarの ArtifactId
  • 8090 —生成されたスタブが実行されるポート

4. 契約が破られたとき

コンシューマー側を更新せずに、プロデューサー側で直接契約に影響を与える変更を行うと、これにより契約が失敗する可能性があります。

たとえば、プロデューサー側でEvenOddControllerリクエストURIを/validate / change /prime-numberに変更するとします。

この変更をコンシューマーに通知しなかった場合でも、コンシューマーはリクエストを / validate / prime-number URIに送信し、コンシューマー側のテストケースはorg.springframework.webをスローします。 .client.HttpClientErrorException:404 NotFound

5. 概要

Spring Cloud Contractが、サービスコンシューマーとプロデューサーの間のコントラクトを維持し、コントラクトを壊すことを心配せずに新しいコードをプッシュできるようにする方法を見てきました。

そして、いつものように、このチュートリアルの完全な実装は、GitHubにあります。