测试基础 单体微服务的测试策略

CKL的思考 · 2022年10月21日 · 最后由 恒温 回复于 2022年11月05日 · 9429 次阅读

随着业务复杂度的提升,技术架构的微服务化已经非常普遍了,如何针对微服务化的产品进行测试,也有了很多的测试策略可以做选择,但是对于单体微服务的测试方案,却比较少有人提起。本文来聊聊这方面的测试策略。

01

如上图,从技术架构的角度上看,现在的多数产品是由前端组件 +Nginx 代理 + 各类微服务 + 数据层 + 系统层及一些外部依赖构成的。针对这个级别的测试策略,就非常的多了,本文暂不展开讲,后续再讨论。

如果把微服务拆开,只关注微服务之间的关联关系,这层是接口测试重点关注的对象。多个微服务通过 REST/RPC 协议进行调用,测试通过接口调用来模拟,完成对应功能的测试,也诞生了类似契约测试的方法论。

再往下拆分,针对单体的微服务,我们如何着手测试?大部分人可能就会归结为单元测试,因为到了这一层,很难有完整的业务需求被实现,测试难度也会大增(毕竟很多测试是不会看代码的)。从 ROI 上来说,效果可能会不理想。但如果做好了,对系统的可测试性和质量保障会有质的提升。

02

针对单体的微服务,可以从 4 个层次来做测试。

请求资源层:一般情况下在 Controller 层实现,这里关注的是服务如何对外提供服务,是 Rest 协议还是 RPC 协议?请求方法是否符合规范,还是只有一种 POST 请求?(关于 Post 请求和 Restful API 的争论,笔者更倾向于后者,但也不争论,看团队的情况)。同时,还要关注是否有鉴权行为。这里还需要关注一些非业务的请求处理,比如需要写到日志系统里的信息,其他非业务需要的接口(如健康检查、配置上报与获取之类的),这部分的测试往往很容易被忽略。如果出问题,在业务上也比较难被发现,甚至发现不了。

业务逻辑 + 数据处理:一般情况是在 Service 层和 Entity 层这里是业务逻辑处理的实体,大部分的业务逻辑都在这里被实现,这里也是我们常讲的单元测试的重点区域,目前支持单元测试的工具也非常的多,常见的有 Junit5,TestNG 以及一些框架自带的功能。单元测试除了是一种有用的测试策略外,还是一种强大的设计工具,尤其是与测试驱动开发相结合。

数据存储:指的是与数据库交付的场景,这里会见了的问题一般是数据连接不上,网络波动等。这种场景虽然很难出现和模拟,但我们需要对这些异常做充分的处理,以便当问题真的出现时,能够快速定位到。同时,为了程序的健壮性,也可以做出一些容错处理。

外部依赖:由于业务上的需要,每个微服务可能会去访问其他微服务,在这里,要注意避免网络隔离引起的错误(在容器化的部署环境下,网络问题更为复杂,需要特别关注),同时还要考虑网络延迟和中断引发的业务问题,需要被更优雅的处理,避免出现数据不一致的情况出现。特别是当依赖的内容不是本系统,而是其他系统时,更要注意数据一致性的问题。

03

有人可能会有疑问:有必要测试得这么细?业务测试都来不及,而且这些看起来和业务也没什么关系,不是一直强调交付价值嘛,这有什么价值?个人认为,细致的微服务测试对测试的价值有以下几点:

  1. 更清晰地了解业务实现:现在的微服务架构非常复杂,许多测试场景并不能通过简单的前端场景就能覆盖到,典型的业务比如查询,在以前,查询数据就是从数据库里来,但是现在,可以存放数据的来源非常得多,除了数据库,还有可能是 Redies,ES,文件等等,如果不了解这些实现,就很难去做针对性地覆盖;

  2. 更好的定位问题:测试人员还是应该学会如何更好地去定位问题,既提高了自己的能力,也提升了对团队的影响力,不好么?

  3. 避免遗漏场景:比如上文提到的请求资源和外部依赖,很难从更上层去验证,如果从单服务的角度来看,就很容易被验证。

  4. 更好地交流:与开发共同频的交流,而不是别人说什么你都不知道,也容易被忽悠。

  5. 提升自己的能力,拓宽自己的思路,这点就不细说了吧。

所以,在允许的情况下,多做一些这类的测试,也是个不错的选择。千里之堤,溃于蚁穴,质量的构建也是从这点点滴滴积累起来的。

但是这里也需要注意一点,并不是所有的单体微服务都需要这么认真的去测试,因为有些微服务的功能相对单一,或者是一些业务逻辑不是很复杂的服务,可以不需要过多的关注。在执行此类测试时,需要注意选择合适的微服务去验证。

04

关于单元测试,在整理资料的时候,遇到一个词:test doubles,说的是什么呢,指的是为了达到测试目的并且减少被测试对象的依赖,使用 “替身” 代替一个真实的依赖对象,从而保证了测试的速度和稳定性。这不就是我们常说的 Mock 吗?原来还是自己想简单了。

test doubles 一般会包含 4 类:Dummy、Fake、Stub 和最常见的 Mock。举一个简单的例子来说明下。

当我们有个业务需要访问通过数据库查询信息或者插入数据时:

Fake:我们可以直接 fake 一个数据库(现在很多 IDE 都会带)

Stub:我们向这个 fake 的数据库中插入 3 个数据,就可以直接获取这三个数据的返回值(可以理解为硬编码只返回这三个值)

Mock:插入数据时,我们只关注是否调用了插入数据这个接口,至于调用之后的预期结果是否正确,那不是我们关心的事,那是提供这个接口的人应该关心的事儿,

Dummy?Dummy 一般是直接定义一个对象就好了。

现在,你的思路是不是被打开了?测试是不是可以更好玩?

原文链接:https://mp.weixin.qq.com/s/smIQjVU1gpSD9wd44YievA

共收到 13 条回复 时间 点赞

卷起来卷起来,生活不易,小猫咪卖艺~

学习了赞👍🏻

学习了😀

如上图,从技术架构的角度上看,现在的多数产品是由前端组件 +Nginx 代理 + 各类微服务 + 数据层 + 系统层及一些外部依赖构成的。针对这个级别的测试策略,就非常的多了,本文暂不展开讲,后续再讨论。

这个也想听听大佬的做法,能出一篇文章么?

干饭狂人 回复

好的,下周安排

学习!

学习了

CKL的思考 微服务的测试策略思考 中提及了此贴 10月27日 09:10
CKL的思考 微服务的测试策略思考 中提及了此贴 10月27日 09:10

学习了,第一次接触这方面的

  1. 先从架构层面看看,有没有必要拆的很细,没必要为了微服务而微服务
  2. 对于权限,限流这种,没有必要过度设计,最好在入口控制
  3. 做好链路可视化
  4. 很多单体微服务并不对外直接提供接口,可能只能通过内部 rpc 请求,实在要测,再写一个对外的微服务专门用来做测试,去调用其他单体微服务。
恒温 回复

嗯,在文章中也提到了,并不是所有的微服务都需要这么细的拆解。 在一些核心微服务上才会有这么细粒度的测试。对于微服务从宏观上的测试策略,在另一篇中有说明。https://testerhome.com/topics/34678

CKL的思考 微服务间的测试策略 中提及了此贴 11月03日 09:18
CKL的思考 微服务间的测试策略 中提及了此贴 11月03日 09:18
恒温 回复

"再写一个对外的微服务专门用来做测试"
可以写一个通用桩来解决,client 桩、内部服务桩,内部服务桩用来做依赖服务的 mock,每个服务都可以细致化的来测试,之前我们这么测代码覆盖率可以跑到 90%+

homin 回复

这个思路不错。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册