Spring系列学习之Spring Cloud Contract测试消息传递

英文原文:https://spring.io/projects/spring-cloud-contract

目录

概述

特性

Spring Boot配置

Server / Producer方面

Client / Consumer方面

快速开始

学习

文档

示例


概述

Spring Cloud Contract是一个总体项目,其中包含帮助用户成功实施消费者驱动合同方法的解决方案。目前,Spring Cloud Contract包含Spring Cloud Contract Verifier项目。

Spring Cloud Contract Verifier是一个支持基于JVM的应用程序的消费者驱动合同(CDC)开发的工具。它附带了用Groovy或YAML编写的合同定义语言(DSL)。合同定义用于生成以下资源:

  •     默认情况下,在对客户端代码(客户端测试)进行集成测试时,WireMock(HTTP Server Stub)将使用JSON存根定义。测试代码仍然必须手工编写,测试数据由Spring Cloud Contract Verifier生成。
  •     如果你使用消息路由消息路由。我们正在与Spring Integration,Spring Cloud Stream和Apache Camel集成。但是,如果您愿意,可以设置自己的集成。
  •     验证测试(默认情况下,在JUnit或Spock中)用于验证API的服务器端实现是否符合合同(服务器测试)。 Spring Cloud Contract Verifier生成完整测试。

Spring Cloud Contract Verifier将TDD提升到软件架构的水平。

要了解Spring Cloud Contract如何支持其他语言,请查看此博客文章。

特性


在尝试测试与其他服务通信的应用程序时,我们可以执行以下两项操作之一:

  •     部署所有微服务并执行端到端测试
  •     模拟单元/集成测试中的其他微服务

两者都有其优点,但也有很多缺点。让我们关注后者。
部署所有微服务并执行端到端测试

好处:

  •     模拟生产
  •     测试服务之间的真实通信


缺点:

  •     为了测试一个微服务,我们必须部署6个微服务,几个数据库等。
  •     将进行测试的环境将被锁定用于单个测试套件(即,在此期间没有其他人能够运行测试)。
  •     很长时间跑
  •     很晚的反馈
  •     非常难以调试


在单元/集成测试中模拟其他微服务

好处:

  •     非常快速的反馈
  •     无基础设施要求


缺点:

  •     服务的实现者创建存根,因此他们可能与现实无关
  •     你可以通过测试和生产失败去生产


为了解决上述问题,创建了带有Stub Runner的Spring Cloud Contract Verifier。他们的主要想法是给你非常快速的反馈,而不需要建立整个微服务世界。

Spring Cloud Contract Verifier功能:

  •     确保HTTP / Messaging存根(在开发客户端时使用)正在执行实际的服务器端实现
  •     促进验收测试驱动开发方法和微服务架构风格
  •     提供一种方法来发布在通信双方立即可见的合同中的更改
  •     生成服务器端使用的样板测试代码

Spring Boot配置


有关详细的分步指南,请查看文档。 您可以在下面找到简化版本。

Server / Producer方面

在服务器(HTTP)/生产者(消息传递)方面添加Spring Cloud Contract Verifier Maven / Gradle插件。 我们假设我们项目的组ID是com.example,工件id是http-server

在配置中传递的测试的基类可能看起来像这样(我们假设我们正在使用[Rest Assured](http://rest-assured.io/)并且我们想要为FraudDetectionController执行CDC 你在写)



package com.example;

// imports

public class MvcTest {

  @Before
  public void setup() {
    RestAssuredMockMvc.standaloneSetup(new FraudDetectionController());
  }

}

src/test/resources/contracts中添加一个Contract定义。 例如名为shouldMarkClientAsFraud.groovy



org.springframework.cloud.contract.spec.Contract.make {
  request {
    method 'PUT'
    url '/fraudcheck'
    body("""
    {
      "clientId":"1234567890",
      "loanAmount":99999
    }
    """)
    headers {
      header('Content-Type', 'application/vnd.fraud.v1+json')
    }
  }
response {
  status 200
  body("""
  {
    "fraudCheckStatus": "FRAUD",
    "rejectionReason": "Amount too high"
  }
  """)
  headers {
    header('Content-Type': 'application/vnd.fraud.v1+json')
  }
 }
}

如果你必须添加一个插件,将为你生成测试和存根。

Maven




		
			
				org.springframework.cloud
				spring-cloud-contract-maven-plugin
				${spring-cloud-contract.version}
				true
				
					com.example.MvcTest
				
			
		
	

Gradle



buildscript {
    repositories {
      mavenCentral()
    }
    dependencies {
      classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootPluginVersion}"
      classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${springCloudContractVersion}"
    }
}

apply plugin: 'spring-boot'
apply plugin: 'spring-cloud-contract'

dependencyManagement {
    imports {
      mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${springCloudDependencies}"
    }
}

dependencies {
    testCompile "org.springframework.cloud:spring-cloud-starter-contract-verifier"
}

contracts {
	baseClassForTests = 'com.example.MvcTest'
}

一旦您尝试从合同构建应用程序,将在/generated-test-sources/contracts下的输出文件夹中生成测试。



package org.springframework.cloud.contract.verifier.tests;

// imports

public class ContractVerifierTest extends MvcTest {

  @Test
  public void validate_shouldMarkClientAsFraud() throws Exception {
    // given:
      MockMvcRequestSpecification request = given()
          .header("Content-Type", "application/vnd.fraud.v1+json")
          .body("{\"clientId\":\"1234567890\",\"loanAmount\":99999}");

    // when:
      ResponseOptions response = given().spec(request)
          .put("/fraudcheck");

    // then:
      assertThat(response.statusCode()).isEqualTo(200);
      assertThat(response.header("Content-Type")).isEqualTo("application/vnd.fraud.v1+json");
    // and:
      DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
      assertThatJson(parsedJson).field("fraudCheckStatus").isEqualTo("FRAUD");
      assertThatJson(parsedJson).field("rejectionReason").isEqualTo("Amount too high");
  }
}

一旦您通过并重新运行工件的构建和安装,Spring Cloud Contract Verifier就会将合同转换为HTTP服务器存根定义。 目前我们正在支持WireMock。 存根将出现在stubs/mappings/下的输出文件夹中,如下所示:



{
  "uuid" : "6c509a40-18f3-498c-a19c-c9f8b56957de",
  "request" : {
    "url" : "/fraudcheck",
    "method" : "PUT",
    "headers" : {
      "Content-Type" : {
        "equalTo" : "application/vnd.fraud.v1+json"
      }
    },
    "bodyPatterns" : [ {
      "matchesJsonPath" : "$[?(@.loanAmount == 99999)]"
    }, {
      "matchesJsonPath" : "$[?(@.clientId == '1234567890')]"
    } ]
  },
  "response" : {
    "status" : 200,
    "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}",
    "headers" : {
      "Content-Type" : "application/vnd.fraud.v1+json"
    }
  }
}

CDC(消费者驱动合同)背后的想法是分享通信双方之间的合同。 Gradle和Maven插件通过使用存根分类器生成带有存根和合约定义的jar来帮助您实现这一点。 只需将其上传到某个中央存储库,其他人可以将其重新用于集成测试。

Client / Consumer方面

在客户端(HTTP)/使用者(消息传递)方面,它足以为正确的Spring Cloud Contract Stub Runner实现提供依赖性。 在这种情况下,因为我们的示例包含与WireMock的HTTP通信作为HTTP Server Stub。 我们将选择以下依赖项:

Maven




  
    
      org.springframework.cloud
      spring-cloud-dependencies
      ${spring-cloud-dependencies.version}
      pom
      import
    
  



  
    org.springframework.cloud
    spring-cloud-starter-contract-stub-runner
    test
  


Gradle



buildscript {
    repositories {
      mavenCentral()
    }
    dependencies {
      classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootPluginVersion}"
    }
}

apply plugin: 'spring-boot'

dependencyManagement {
    imports {
      mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${springCloudDependencies}"
    }
}

dependencies {
    testCompile "org.springframework.cloud:spring-cloud-starter-contract-stub-runner"
}

最后一步是在测试中设置Stub Runner以自动下载所需的存根。 要实现这一点,您必须传递@AutoConfigureStubRunner注释。 该注释具有一组您可以设置的属性。 如果您不喜欢这种方法,您也可以在测试属性中设置这些值。

对于Spring Cloud Contract 1.2.x



@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureStubRunner(ids = {"com.example:http-server:+:stubs:8080"}, workOffline = true)
public class LoanApplicationServiceTests {

对于从2.0.x开始的Spring Cloud Contract



@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureStubRunner(ids = {"com.example:http-server:+:stubs:8080"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
public class LoanApplicationServiceTests {

这样,具有组ID com.example的工件,工件id http-server,在最新版本中,具有存根分类器将在端口8080处注册。由于传递了workOffline标志,因此将不从远程存储库下载存根 - 它 将在当地的Maven回购中搜索。 一旦您的测试上下文启动,执行以下代码将不会导致404,因为Spring Cloud Contract Stub Runner将自动启动测试中的WireMock服务器并使用从服务器端生成的存根来提供它。



HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Type", "application/vnd.fraud.v1+json");
String response = restTemplate.exchange("http://localhost:8080/fraudcheck", HttpMethod.PUT,
            new HttpEntity<>("{\"clientId\":\"1234567890\",\"loanAmount\":99999}", httpHeaders),
            String.class);
assertThat(response).isEqualTo("{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}");

快速开始

使用Spring Initializr引导您的应用程序。

学习

文档

每个Spring项目都有自己的; 它详细解释了如何使用项目功能以及使用它们可以实现的功能。

2.1.0 RC3 PRE CURRENT Reference Doc. API Doc.
2.0.3 SNAPSHOT CURRENT Reference Doc. API Doc.
2.0.2 CURRENT GA Reference Doc. API Doc.
1.2.6 SNAPSHOT CURRENT Reference Doc. API Doc.
1.2.5 CURRENT GA Reference Doc. API Doc.
1.1.6 SNAPSHOT Reference Doc. API Doc.
1.1.5 GA Reference Doc. API Doc.
1.0.5 SNAPSHOT Reference Doc. API Doc.
1.0.4 GA Reference Doc. API Doc.

示例

尝试一些例子:

  • Spring Cloud Contract Samples (Edgware) 使用Boot 1.5和Edgware版本列的Spring Cloud Contract样本
  • Spring Cloud Contract Samples (Finchley) 使用Boot 2.x和Finchley发布列表进行Spring Cloud Contract的示例
  • Spring Cloud Contract workshops 与Spring Cloud合同的研讨会
  • Spring Cloud Contract with NodeJS 您可以在此处阅读有关Polyglot方法的更多信息https://spring.io/blog/2018/02/13/spring-cloud-contract-in-a-polyglot-world

你可能感兴趣的:(Spring,Cloud,Contract)