You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

11 KiB

09 | 微服务接口怎么用Mock解决混乱的调用关系

你好,我是陈磊。

欢迎你继续和我一起学习接口测试,到目前为止,我们已经学习了接口测试的逻辑模拟,也就是测试辅助工具和测试脚本代码,也学习了如何选取和通过代码调用测试参数,掌握了这些内容,你就算是一个接口测试的老手了。无论你的被测接口是一个你熟悉的协议,还是一个陌生的协议,它们都不会耽误你的工作进度了。

这节课是我们专栏的最后一节课,我想给你讲一讲关于微服务的接口测试。

现如今在我的工作中我主要面对的就是微服务测试每个服务都是RESTful接口。在最开始的微服务改造过程中我的测试其实比之前的业务测试更容易每一个接口通过测试框架来编写测试脚本就可以完成执行了而且一次写完后再通过平台调用也显得很轻松。但是这种美好的场景并没有持续多久。为什么呢 你先听听我的故事。

微服务下混乱的调用关系

开发团队开始采用微服务架构开发系统的时候我的测试团队也开始同步学习对应的测试技术我也像从前一样逐步封装自己的测试框架并且采用Postman和Python代码完成接口测试脚本的快速积累同时引入了参数类完成了Excel参数的封装调用。

在开始的一些项目中,只要开发工程师提交了代码仓库主干的合并请求后,除去代码的静态扫描外,持续集成平台会自动调取一个开源的智能化单元测试框架,来完成单元测试,通过后它会自动部署被测系统,然后再执行测试脚本,这整个流程全部是流水线自动驱动完成的。

一般来说开发工程师在开发前期就已经定义好了微服务接口测试工程师和开发工程师几乎是同步开始进行各自的开发任务。但是这种和谐的工作场景很快就被蜘蛛网一样的微服务调用关系给破坏了几乎所有的项目都会出现相互依赖的关系比如说服务A依赖服务B服务B依赖服务C如下图所示

这种混乱主要体现在:

  • 当持续集成流水线部署服务A的时候由于对应的开发工程师团队也在做同步改造导致测试环境的服务B不可用

  • 由于服务B依赖服务C而服务C还没有开发完成导致即使服务A和服务B都没问题但也没有办法完成服务A的接口测试。

其实这种服务A依赖服务B服务B依赖服务C的依赖方式还算简单还有更多微服务随着开发越来越复杂服务之间的调用关系就像蜘蛛网一样错乱让你摸不清外部依赖到底有几层以及一个接口到底依赖了几个外部接口。

这就导致了虽然被测系统已经开发完成,测试脚本也准备就绪,但是测试工作就是没办法进行的悲惨结局。面对这种局面,我当时心里确实很不舒服,因为自己做了那么多努力,到头来却被一个不是由自己负责的服务卡住了工作进度,这感觉就像是用尽了全身的力气,却一拳打到了棉花上,自己有再多的劲儿也没处使。

Mock框架的抉择用什么实现服务B的替身

那作为测试工程师,面对这样的情形,我们该怎么办呢?

我当时想到的就是使用Mock服务。其实Mock服务是一个错误的说法关于这一点我推荐你看一下Martin Flower的这篇叫做TestDouble的文章一般我们将TestDouble服务叫做测试替身但是如今的国内业界里绝大部分人已经习惯了叫Mock服务因此在这里我们也还是叫Mock服务。

针对混乱的调用关系我的思路是我的被测服务就是服务A那么我不用管服务B是不是好用我只要保障服务A能够走完流程就可以完成接口测试任务了。循着这个思路我只要用Mock服务伪装成服务B就万事大吉了我也不用再关心服务B到底调用了多少服务。

但是在选取Mock服务框架时我又面临着一个抉择那就是用什么来实现服务B的替身。现在可以实现Mock服务的框架特别多但绝大部分都要求你有很好的代码基础每做一个Mock服务其实就是做了一个简单的服务B不同的是它不需要实现原有服务B负载的处理逻辑只要能按服务B的处理逻辑给出对应返回就可以了。

因此有些团队也会把这样的服务叫做挡板系统这个名字很形象。也就是说我给了Mock服务B的请求参数它只要按照约定好的返回给我参数就可以了至于一系列其它验证或者微服务调用都不在Mock服务的设计内这就像你对着墙打乒乓球一样墙是你假设的对手会把你打过去的球挡回来而你要做的就是接住墙挡回给你的球。

那么到底应该怎么选择Mock服务框架呢

首先你要基于自己和团队的技术栈来做选择这决定了你完成服务B替身的速度。你要知道无论服务B的替身做得多么完美它只是一个Mock它存在的意义就是帮助你快速完成服务A的接口测试工作因此选择一个学习成本低、上手快并且完全适合你自己技术栈的Mock框架能让你的测试工作事半功倍。

其次你要让写好的Mock服务容易修改和维护。Mock服务就是一个在测试过程中替代服务B的替身就和拍电影时的替身演员一样替身演员可能有好几个需要在不同地方拍摄不同的电影片段。Mock服务可能只有一个也有可能有好几个为了不同的调用或者测试而存在。但是Mock服务会随着服务B的变化而变化如果服务B的请求参数和返回参数有变化那么Mock服务也要能快速完成修改并且能马上发挥作用。因此一个非常容易维护的Mock服务框架才更能马上快速投入使用快速发挥作用。

如果你的团队技术基础很好开发能力很强那么我建议你用对应语言的Mock框架例如Java语言的Mockito框架和Python语言的mock框架

如果你的团队技术基础相对比较薄弱,那么我推荐你看看moco这个框架在开发Mock服务的时候提供了一种不需要任何编程语言的方式你可以通过撰写它约束的Json建立服务并通过命令启动对应的服务这就可以快速开发和启动运行你需要的Mock服务。

更重要的是Json格式的数据文件可以独立完成Mock的服务设计而且Json的学习成本和Python语言相比就如同小学一年级的数学和高中数学之间的难度差距一样就更别说和犹如高等数学的Java语言相比较了。如果你想详细的学习moco可以直接去它在Github上的项目空间那里有详细的使用说明和示例代码。

我的Mock服务设计经验

在选择好Mock框架后你就可以酣畅淋漓地完成各个外部依赖服务的解耦工作了但是关于Mock服务我还想告诉你一些我的设计经验。

**首先,简单是第一要素。**无论原服务B处理了多么复杂的业务流程你在设计服务B的Mock服务时只要关心服务B可以处理几种类型的参数组合对应的服务都会返回什么样的参数就可以了。这样你就能快速抓住Mock服务B的设计核心也能快速完成Mock服务B的开发。

**其次处理速度比完美的Mock服务更重要。**一个Mock服务要能按照原服务正确又快速地返回参数你不需要把大量的时间都浪费在Mock服务的调用上它只是用来辅助你完成接口测试的一个手段。你需要让它像打在墙上的乒乓球一样一触到墙面马上就反弹回来而不能把球打出后需要去喝个茶或者坐下休息一会才能收到反弹回来的球。

如果你的Mock服务很耗时你在只有一个两个服务时可能影响还不是很明显但如果你同时有多个Mock服务或者需要用Mock服务完成性能测试的时候这就会变成一个很严重的问题后续会引发强烈的“蝴蝶效应”使得整个被测接口的响应速度越来越慢。因此你要建立一套快速的Mock服务尽最大可能不让Mock服务占据系统的调用时间。

**最后你的Mock服务要能轻量化启动并且容易销毁。**你要时刻注意Mock服务只是一个辅助服务因此任何一个团队都不希望启动一个Mock服务需要等待5分钟或者需要100M的内存。它要能快速启动、容易修改并且方便迁移。既然Mock服务的定位是轻量化的辅助服务那么它也要容易销毁以便你在完成测试后可以快速且便捷地释放它所占据的资源。

总结

微服务现在已经铺天盖地而来,尤其在中台化战略的推动下,业务中台服务的依赖关系会越来越复杂,并且随着团队内微服务数量越来越多,每个测试团队面临的被测系统都会是一团乱麻,很容易找不到头绪。

为了解决由于微服务间相互依赖而导致的混乱的系统调用关系我建议你尽快掌握一个Mock服务框架这样可以让你在混乱中理清思路快速进行接口测试交付高质量的项目。

最后我要提醒你的是选择Mock的技术栈与选择测试框架的技术栈还是有些区别的在选择Mock技术栈时你重点要考虑的是学习成本把学习成本降到最低才是选择Mock框架的首要关注点。而且你不只要关注自己的学习成本也要关注你所在团队的学习成本因为现在每个项目都有可能需要Mock服务这个时候就要求每一个项目的测试工程师都具备自己独立建设Mock服务的能力在Mock服务的技术选型上还是要以团队整体的技术栈为基础以自己的技术为参考进行选型。

思考题

这节课我讲了在微服务混乱的外部调用下使用Mock外部接口完成被测接口的测试工作文中我也给你推荐了一个快速入门的Mock工具那么你在工作中有没有遇见过被测系统因为外部依赖而不得不阻塞项目进度的时候呢你又是怎么解决的呢

我是陈磊,欢迎你在留言区留言分享你的观点,如果这篇文章让你有新的启发,也欢迎你把文章分享给你的朋友,我们一起沟通探讨。