单体微服务的测试策略

2023-02-01 16:16:27 浏览数 (1)

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

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://martinfowler.com/articles/microservice-testing/

往期推荐:

为什么选JMeter做接口测试?

我理解的敏捷是什么

敏捷研发想表达什么

在职场上拥有选择的权力

敏捷测试系列文章合集

END

标星、点赞、关注三连走起,感谢支持。

如果想阅读更多文章,请关注我的公众号。

0 人点赞