• Spring Cloud Contract简单入门


    一、背景

    1、概述(来着官网的一段介绍)

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

    Spring Cloud Contract Verifier 是一种工具,它支持基于 JVM 的应用程序的消费者驱动契约 (CDC) 开发。它附带了用 Groovy 或 YAML 编写的合同定义语言 (DSL)。

    Spring Cloud Contract

    2、自我理解:

    简单点来说就是提前设置一个已知结果,消费者调用时直接返回该结果,该结果在消费者的程序处理中是否正确,来测试消费者程序。

    3、解决了哪些痛点

    目前很多系统都采用了微服务的开发模式,随着项目规模的不断扩大,服务数量越来越多,服务之间的依赖也越来越密切。不同的团队负责不同的服务开发,其中某个服务发生变动,很多服务也是需要进行修改,这将需要大量的沟通成本和代码修改时间成本。

    4、目前常见测试中:

    单元测试无法测试服务间的连接或接口调用正确性。

    API接口测试是针对业务接口进行,主要是测试接口实现是否完整,且需要依赖具体真实服务。

    集成测试无疑是最佳的,但是需要依赖具体真实服务,且各个服务都需要同时进行测试,其效率很慢。

    契约测试,无需依赖具体真实服务,测试服务间的连接或接口调用正确性 。测试效率快。

    总体来说,契约测试是一个介于单元测试和集成测试的一个阶段,他关注的细粒度比单元测试更粗,但是又无法取代集成测试。

    二、实现

    目前官网和很多博客文章都介绍了,远程库使用契约测试的方法。我这边就介绍一下本地库实现方法。基本一致,只不过读取jar是读取本地。

    服务提供者

    在服务端编写一个简单的接口,判断数字是否为负数。

    1. @RestController
    2. public class NumberController {
    3. @GetMapping("/value/number")
    4. public String isMinus(@RequestParam("number") Integer number) {
    5. return number < 0 ? "true" : "false";
    6. }
    7. }

    pom文件

    JUNIT,不加这个可能无法进行install。

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframework.cloudgroupId>
    4. <artifactId>spring-cloud-dependenciesartifactId>
    5. <version>Hoxton.SR12version>
    6. <type>pomtype>
    7. <scope>importscope>
    8. dependency>
    9. <dependency>
    10. <groupId>org.springframework.cloudgroupId>
    11. <artifactId>spring-cloud-starter-contract-verifierartifactId>
    12. <version>3.1.1version>
    13. <scope>testscope>
    14. dependency>
    15. <dependency>
    16. <groupId>org.springframework.bootgroupId>
    17. <artifactId>spring-boot-starter-webartifactId>
    18. dependency>
    19. <dependency>
    20. <groupId>junitgroupId>
    21. <artifactId>junitartifactId>
    22. <scope>testscope>
    23. dependency>
    24. dependencies>
    25. <build>
    26. <resources>
    27. <resource>
    28. <directory>src/main/resourcesdirectory>
    29. <filtering>truefiltering>
    30. resource>
    31. resources>
    32. <plugins>
    33. <plugin>
    34. <groupId>org.springframework.cloudgroupId>
    35. <artifactId>spring-cloud-contract-maven-pluginartifactId>
    36. <version>3.1.1version>
    37. <extensions>trueextensions>
    38. <configuration>
    39. <testFramework>JUNITtestFramework>
    40. <baseClassForTests>com.lin.test.BaseTestClassbaseClassForTests>
    41. configuration>
    42. plugin>
    43. <plugin>
    44. <groupId>org.springframework.bootgroupId>
    45. <artifactId>spring-boot-maven-pluginartifactId>
    46. <version>2.3.12.RELEASEversion>
    47. <configuration>
    48. <mainClass> com.lin.test.MainApplicationmainClass>
    49. configuration>
    50. <executions>
    51. <execution>
    52. <goals>
    53. <goal>repackagegoal>
    54. goals>
    55. execution>
    56. executions>
    57. plugin>
    58. plugins>
    59. build>

    接下来需要新建基础测试类以及存根,注意存放目录,如图所示:

    测试类

    1. @RunWith(SpringRunner.class)
    2. @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
    3. @DirtiesContext
    4. @AutoConfigureMessageVerifier
    5. public class BaseTestClass {
    6. @Autowired
    7. private NumberController numberController;
    8. @Before
    9. public void setup() {
    10. StandaloneMockMvcBuilder standaloneMockMvcBuilder = MockMvcBuilders.standaloneSetup(numberController);
    11. RestAssuredMockMvc.standaloneSetup(standaloneMockMvcBuilder);
    12. }
    13. }

    存根(groovy文件)

    1. import org.springframework.cloud.contract.spec.Contract
    2. Contract.make {
    3. description "should return true when number input is minus"
    4. request {
    5. method GET()
    6. url("/value/number") {
    7. queryParameters {
    8. parameter("number", "-1")
    9. }
    10. }
    11. }
    12. response {
    13. body("true")
    14. status 200
    15. }
    16. }
    1. import org.springframework.cloud.contract.spec.Contract
    2. Contract.make {
    3. description "should return false when number input not minus"
    4. request {
    5. method GET()
    6. url("/value/number") {
    7. queryParameters {
    8. parameter("number", "1")
    9. }
    10. }
    11. }
    12. response {
    13. body("false")
    14. status 200
    15. }
    16. }

    到此服务提供者编写完成,我们接下来进行mvn clean install 就会生成测试类

     构建还会在我们的本地Maven存储库中添加存根jar。

     服务消费者

    1. @RestController
    2. public class BasicMathController {
    3. @Autowired
    4. private RestTemplate restTemplate;
    5. @GetMapping("/calculate")
    6. public String checkOddAndEven(@RequestParam("number") Integer number) {
    7. HttpHeaders httpHeaders = new HttpHeaders();
    8. httpHeaders.add("Content-Type", "application/json");
    9. ResponseEntity responseEntity = restTemplate.exchange(
    10. "http://localhost:8090/value/number?number=" + number, HttpMethod.GET,
    11. new HttpEntity<>(httpHeaders), String.class);
    12. return responseEntity.getBody();
    13. }
    14. }

    pom文件

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframework.cloudgroupId>
    4. <artifactId>spring-cloud-dependenciesartifactId>
    5. <version>Hoxton.SR12version>
    6. <type>pomtype>
    7. <scope>importscope>
    8. dependency>
    9. <dependency>
    10. <groupId>org.springframework.cloudgroupId>
    11. <artifactId>spring-cloud-contract-wiremockartifactId>
    12. <version>3.1.1version>
    13. <scope>testscope>
    14. dependency>
    15. <dependency>
    16. <groupId>org.springframework.cloudgroupId>
    17. <artifactId>spring-cloud-starter-contract-stub-runnerartifactId>
    18. <version>3.1.1version>
    19. <scope>testscope>
    20. dependency>
    21. <dependency>
    22. <groupId>org.springframework.bootgroupId>
    23. <artifactId>spring-boot-starter-webartifactId>
    24. dependency>
    25. <dependency>
    26. <groupId>org.springframework.bootgroupId>
    27. <artifactId>spring-boot-starter-data-restartifactId>
    28. dependency>
    29. <dependency>
    30. <groupId>junitgroupId>
    31. <artifactId>junitartifactId>
    32. <scope>testscope>
    33. dependency>
    34. <dependency>
    35. <groupId>org.examplegroupId>
    36. <artifactId>provider-testartifactId>
    37. <version>1.0-SNAPSHOTversion>
    38. dependency>
    39. dependencies>
    40. <build>
    41. <resources>
    42. <resource>
    43. <directory>src/main/resourcesdirectory>
    44. <filtering>truefiltering>
    45. resource>
    46. resources>
    47. <plugins>
    48. <plugin>
    49. <groupId>org.springframework.bootgroupId>
    50. <artifactId>spring-boot-maven-pluginartifactId>
    51. <version>2.3.12.RELEASEversion>
    52. <configuration>
    53. <mainClass> com.lin.test.MainApplicationmainClass>
    54. configuration>
    55. <executions>
    56. <execution>
    57. <goals>
    58. <goal>repackagegoal>
    59. goals>
    60. execution>
    61. executions>
    62. plugin>
    63. plugins>
    64. build>

    存根运行器

    1. @RunWith(SpringRunner.class)
    2. @SpringBootTest(webEnvironment = WebEnvironment.MOCK)
    3. @AutoConfigureMockMvc
    4. @AutoConfigureJsonTesters
    5. @AutoConfigureStubRunner(ids = {"org.example:provider-test:+:stubs:8090"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
    6. public class BasicMathControllerIntegrationTest {
    7. @Autowired
    8. private MockMvc mockMvc;
    9. @Test
    10. public void given_WhenPassEvenNumberInQueryParam_ThenReturnEven() throws Exception {
    11. mockMvc.perform(MockMvcRequestBuilders.get("/calculate?number=2").contentType(MediaType.APPLICATION_JSON))
    12. .andExpect(status().isOk()).andExpect(content().string("Even"));
    13. }
    14. }
    @AutoConfigureStubRunner这个注解非常重要,这里选择的是本地存根。
    之前以为这样就完事了,调用时报错了。找不到对应maven存储库,找到了默认的。
    

     需要进行设置参数:

    org.apache.maven.user-settings

     到此结束,文章有些粗糙,有哪里不对的,欢迎指正。

  • 相关阅读:
    利用ldt_struct 与 modify_ldt 系统调用实现任意地址读写
    HTML知识小结之CSS
    微服务从代码到k8s部署应有尽有系列(十、错误处理)
    Apache Atlas 50道面试题及参考答案
    小程序图片报错替换
    经典面试题-显式等待与隐式等待
    缺失的数据范围,思维,hduoj
    Notion Like 笔记软件使用教程·学习资源汇总·知识管理方案
    “创新启变 聚焦增长”极狐(GitLab)媒体沟通会,共话智能时代软件开发新生态
    c++ std::cout输出结果错误,只有一堆数字没有指定的字符串?
  • 原文地址:https://blog.csdn.net/Lin_Miao_09/article/details/126848801