前言
Spring contract解决了在开发时,由于不同服务团队之间的进度不一致,导致的测试困难的问题。
为什么需要spring contract
在日常的集成测试中,我们可以通过以下两种方式来进行测试,但是各有优缺点
部署所有微服务并执行端到端测试。
优点:
模拟生产。
测试服务之间的真实通信。
缺点:
要测试一个微服务,我们必须部署6个微服务,几个数据库等。
运行时间很长,稳定性差,容易失败。
非常难以调试,依赖服务不受控制。
在单元/集成测试中模拟其他微服务。
优点:
非常快速的反馈,简单易用。
没有基础设施要求,如DB,网络等。
缺点:
模拟不够真实。
部分场景测试不到。
总结
所以这时候Spring Contract的优势就体现出来了,既可以模拟测试服务间的真实通信,也可以有非常快的反应速度以及简单易用。
接下来我会根据工作中的例子来进行实际操作,然后一步一步的完成spring contract。具体案例有一定的简化与名称修改(涉及到公司保密措施)
Spring contract的实现步骤
1. 作用
服务提供方与消费方共同约定好契约,都按照约定契约进行开发。确保开发的代码满足双方的需求。
2.步骤
服务提供方
step 1:添加依赖与插件
依赖:spring-cloud-contract-verifier - 用于自动生成单元测试代码
插件:spring-cloud-contract-maven-plugin - 同时还需要指定测试基类,在baseClassForTest中指定基类位置。该插件才会自动生成测试类与stubs(存根)
step 2:创建测试基类
根据步骤一中指定的基类位置,创建对应的测试基类。测试基类的作用是用于定义测试需要的环境
step 3:编写待测试的接口
(接口开发完成的情况)接口的返回结果跟契约定义的结果需要一致,否则生成的测试类,断言会不通过,也就无法生成stub jar。这种是契约的正确使用方式,消费者定义契约,验证生产者的接口是否符合契约,符合才能够进行构建
(接口未开发完成的情况)可以不需要接口,只写契约,Maven install时,只需要Mvn clean install -DskipTests,即可跳过verifier的测试,这种是为了将生成的.jason文件移植到mock服务器上。
step 4:添加合同
在合同的默认位置 src/test/resources/contracts 下用Groovy、Kotlin或Yaml编写合同定义语言(DSL)。推荐使用groovy,简单易懂好编写。本次实操使用的就是groovy编写合同。
step 5:Maven install生成stubs-jar
install完成后会生成4个文件,自动测试类(1),合同(2),映射的json(3),存根jar(4),如下图所示:
消费方
step 1:添加依赖
依赖:spring-cloud-contract-stub-runner
step 2:写测试类
1.需要注意@AutoConfigureStubRunner这个注解,是用于自动注入配置一个StubRunner. 也就是使用这个注解才能够调用到具体的打桩服务:
ini
@AutoConfigureStubRunner(
repositoryRoot="https://xxx.xxx.net/repository/contract-test",
ids = "com.xxx:loan:1.0.0-SNAPSHOT:stubs:8090")
2.也可以通过在/src/test/resources目录下增加一个配置文件application-stub.yml文件:
yaml
stubrunner:
stubs-mode: REMOTE
repositoryRoot: https://xxx.xxx.net/repository/contract-test
username: user
password: xxx
ids:
- com.xxx.xxx:1.0.0-SNAPSHOT:stubs:8090
其中的ids格式是:groupId:artifactId:version:classifier:port
然后通过ids去定位到刚刚通过clean install好的那个stub jar 包,然后在指定端口去启动这个stub jar
最终效果
当测试上下文启动,无需启动生产者的服务,在测试类调用生产者的接口不会404,因为Spring Cloud Contract Stub Runner将自动启动测试中的WireMock服务器并使用从服务器端生成的存根来提供返回数据。