一文掌握契约测试

网站建设4年前发布
43 0 0

领域驱动设计因为微服务的流行而再次火了起来,契约测试也是一样。,为了在微服务开发模式下跨团队协调更有效率,提升持续集成流水线自动化水平,契约测试有效弥补了集成测试的不足,强势C位出镜。,本文将通过逐步介绍契约测试是什么,怎么做,有哪些工具,有哪些最佳实践和经验教训,带您一起彻底掌握契约测试。,契约测试(Contract testing)是一种测试技术,它通过以隔离检查集成点上的每个应用的方式,确保应用发送或接收的消息符合调用双方共识,并允许随着时间的推移进行演化。,契约测试主要解决在存在沟通边界情况下,测试替身(Test Double)与生产代码表现可能不一致的问题。在契约测试中,契约由代码生成,保持与现实同步,而且应用可以独立于其它应用而仅基于契约进行快速测试。,由于集成测试容易受到网络缓慢或不可靠,以及服务不可靠等因素的影响而运行缓慢或失败,所以通常会引入测试替身来代替真实外部服务,以快速完成覆盖度更广的测试,让测试真正起到作用。,但是,这样做的同时,带来了测试替身是否可以持续准确表示外部服务的问题。于是,需要单独补充运行一组契约测试,来检查所有对测试替身调用的返回结果总是与对外部服务调用的返回结果相同。,金字塔模型是构建健康、快速、可维护测试集的成熟理论。,20230306004701d79344944dfaa7ae1e2903bdfdc4dd7c56a207658,契约测试适合归属于服务测试(Service Tests)层,因为它们执行得很快,也不需要和外部服务集成来运行。契约测试运行于发布版本之前,为成功集成提供信心。,众所周知,越是在项目生命周期的后期发现Bug,其修复的成本就越高。,20230306004701b9661b372328d9b8b61121d123fd6d404c1c1f899,不同于端到端(E2E)测试,契约测试可以在开发人员推送代码之前运行,在开发阶段提早发现问题。,契约测试还有很多端到端测试不具备的好处:,引入契约测试,还会带来如下福利:,没有两个团队是完全一样的,契约测试也不是万能的,关键要看契约测试可以为团队和项目带来什么。,契约测试可以用于任何需要通信的两个服务,比如Web前端与后端API服务。,在微服务架构体系中,因为存在更多团队独立、服务间调用及服务单独演进的情形,契约测试有了更好更大的用武之地。良好的契约测试,使得开发人员很容易避免版本地狱,是微服务开发和部署的利器。,契约测试主要涉及如下概念术语:,20230306004830c1ef5a728b165368ee548048df2210c2746fc5480,契约测试分为消费者驱动(consumer-driven)和提供者驱动(Provider-driven)两种模式。,消费者驱动更具哲学意义,将API的消费者置于设计过程的核心,来倡导更好的内部微服务设计。该模式的优点在于,只有消费者正在使用的部分会得到测试,而提供者可以自由地更改消费者不使用的任何其它部分,而不必破坏任何现有测试。,提供者驱动思路较为常规,更适合开放数据或系统的场景。,无论采用哪种风格,关键在于获得契约测试的好处,实现引入契约测试的目的。,消费者驱动的契约测试运行步骤如下:,2023030600482966a2fc6594980fe00e57450433bf28a54e9c14861,提供者驱动模式由提供者定义契约并驱动整个过程。,2023030600470743a19d680e93331129f740aa6d5bc57dddacc0994,流行的契约测试工具为:,利用Pact进行契约测试的整个流程示意如下。,2023030600483186ff252266b2638571407922e2e9c119f9f059391,一旦上面的测试通过了,就会在 target/pacts 文件夹中生成一个pact契约文件,文件名称为user-consume-service-user-provider-service.json,文件内容如下:,Pact Broker是一个用于共享消费者驱动的契约,并验证结果的应用程序,对于Pact创建的契约做了优化,但也可以用于任何可以序列化为JSON的契约。,Pact Broker既支持在云上使用,也可以在本地部署。,以下是一个利用Docker Compose来本地部署Pack Broker的描述文件。,以下是Pact Broker启动后的界面样子。,2023030600483246e0e209931bbedb67d61627a1011a9b415679753,接下来就可以使用pack-jvm的pactPublish命令将契约文件发布到Broker。,首先在build.gradle文件中添加需要的配置。,然后,运行如下命令发布契约。,命令执行成功后,即可在Pact Broker上看到已发布的契约。,202303060047098941a6717ac6f79737528972857b2f639212b8766,同时,可以在Broker上查看契约细节。,20230306004709c5adb646341837c0430291388835bfd42529a1822,至此,消费者方已完成契约创建、发布等全部工作。,如下为提供者的生产代码。,以下代码用于提供者对契约的验证。,以下为测试运行结果的样子。,2023030600483242461fb66c7bf48b1a1768e5b5e004ac613fb3265,至此,已完成提供者测试,并证实了契约被正确履行。,在Broker上,可以看到契约被验证通过。,20230306004912a5de91e753cadd10068485fabb4b5f0f4ec944178,至此,消费者、提供者一起完成了整个契约测试。,利用Spring Cloud Contract进行契约测试的过程示意如下。,20230306004912328f51697dcdad0c3211868862874fc5500b6e118,SCC各组件相互关系描述如下。,20230306005227f6c55d950c3f3301a563230e8d22e98e957baf898,SCC允许通过groovy、yaml、代码等多种方式定义契约。,契约中包含在body中定义的消息示例及在matcers中定义的字段匹配器等。,首先创建一个测试基类,以便使用命令来生成测试代码。,测试基类的作用是在每次测试运行之前初始化提供者API和其他配置。,接下来,框架将在maven插件被构建过程调用后,基于契约生成测试代码。,测试代码将向提供者发送带有契约中示例数据的请求,并解析响应,根据契约验证响应。,提供者生成的契约jar文件,可以发布到Nexus、JFrog等构建库中存储,同时和其他maven构建一样,可以通过group Id、artifact id、version等识别和获得。,在消费者端,SCC框架为其提供了一个Stub Runner,它可以获取存根定义并将其注册到WireMock服务器。而该Mock服务器将模拟测试用例提供者的API,以支持消费者验证契约。,因此,首先需要为消费者应用添加stub runner的maven依赖。,以下为消费者契约测试代码。,其中@AutoConfigureStubRunner用于指定契约存根的maven组件信息,包括group id、artifact id和端口号。然后stub runner就可以从本地或远程存储库获取存根定义。,如下测试代码将调用端口为6565的mock服务器,并对响应进行断言。,契约测试有如下最佳实践。,契约测试需要跨团队协作,尽快让各方都加入进来,就模式和工具等各方面达成一致,否则很快就会遇到麻烦。,契约测试是一种新型的测试方法,即使拥有丰富的单元测试、集成测试等其它测试类型的丰富经验,也并不能代表可以编写有价值、可维护的契约测试,真正的挑战在于如何处理API和契约随时间的变化。,工具并不能代替彼此之间的交流,契约测试也是一样,至少在初始阶段。而在后期,消费者更新契约之前,仍然有必要事先与提供者进行讨论。,Spring Cloud Contract不太适合消费者驱动的契约测试,总是需要消费者等待提供者完成相关工作,而Pact则不需要这种等待。,另外,SCC使用Groovy编写的契约需要手动与消费者代码保持同步,而Pact的API则相当成熟,会自动化生成各种代码和文件。同时SCC在提供者端提供的的设置和断言选项较少。Pact的社区支持也相对较好。,Pact对多语言的支持也更好。,可以使用swagger-diff工具比较两个版本的API,swagger-diff工具可以用来比较两个Swagger API规范,并将结果输出到HTML或Markdown文件中。,202303060052288413286343ed4fa394f886eca2a37afab8217d178,2023030600471487078921624295a90b7730599f2aec00056b3a164

© 版权声明

相关文章