微服务概述
微服务应用是一系列自治服务的集合,每个服务只负责完成一块功能,这些服务共同合作来就可以完成某些更加复杂的操作。与单体的复杂系统不同,开发者需要开发和管理一系列相对简单的服务,而这些服务可能以一些复杂的方式交互。这些服务之间的相互协作是通过一系列与具体技术无关的消息协议来完成的,这些协议可能是点到点形式的,也可能是异步形式的。
这种想法听起来很简单,但是它确实能够显著降低复杂系统开发过程中的摩擦和冲突。传统的软件工程实践倡导设计良好的系统都应该具备高内聚、低耦合的特点。具备这些特性的系统更加易于维护,并且在面对变更时,也更加容易适应和扩展。
内聚度是用来衡量某个模块中的各个元素属于一个整体的紧密程度的指标,耦合度则是衡量一个元素对另一个元素的内部运行逻辑的了解程度的指标。在讨论内聚度时,罗伯特·C.马丁(Robert C. Martin)的单一职责原则是一种非常有用的方式:
将那些因相同原因而修改的内容聚合到一起,将那些因不同原因而修改的内容进行拆分。
在单体应用中,开发者会在类、模块、类库的层面来设计功能属性;而在微服务应用中,开发者的目标则变成了可独立部署的功能单元——要为这些功能单元设计功能属性。单个微服务应该是高内聚的:它应该只负责应用的某一个功能。同样,每个服务对其他服务的内部运行逻辑知道得越少,就越容易对自己的服务或者功能进行修改,而不需要强迫其他服务一起进行修改。
何为全链路测试?
个人认为,链路可以分为业务链路和调用链路,调用链路主要指从请求发起方到结果返回所途径各种服务/中间件产生的路径,可以理解为单系统下的某一功能模块。而业务链路则是多个业务关联的场景组合产生的链路调用集合,例如淘宝添加购物车->提交订单->支付这个场景,所以全链路必然包含多个业务关联场景涉及的调用链路。
正如上所述,微服务的下单支付场景就被拆分成多个域共同协作实现,那么全链路测试必然是要测试整条业务链路,也就是说针对一笔下单支付业务请求,测试同学不仅在关注输入输出结果正确性,还需要关注收单、支付、金融等域的落DB数据是否正确性。
域内测试
顾名思义,域内测试就是单域(服务)测试,例如收单域。需要注意的是单域并非单接口,域和接口是一对多的关系,也就是说单域包含多个接口对外提供不同的服务,只是这些接口业务比较相近,统一划归到某个域了。
因此,域内测试可以等同于接口测试,微服务下更多是非Http协议实现的接口,例如基于TCP协议的RPC。所以市面上的接口测试工具,如postman,jmeter都不能直接拿来用了,需要测试同学搭建符合自己需求的测试框架。
全链路测试,为什么不是银弹?
下面分析以下三个原因并结合几个场景说明阐述下:
成本高
- 自动化用例开发成本高
这点无需赘言,无论单体还是微服务,自动化成本都不低。全链路下自动化成本更高,因为全链路用例涉及到多域的流程编排,处理服务间各种异常重试情况(超时、网络异常), 各域的输出断言,这无疑大大增加一条用例开发成本。
- 问题排查成本高
大多数测试同学对于本域服务比较熟悉,如果全链路用例出现外域报错,如果自己解决不了,势必要请求负责域的同学解决,大家总有自己的事情要做,不可能随时随地随叫随到吧。
这个跨部门的沟通和协作效率严重低下,而且人员变动、系统变动都会直接影响问题排查结果。
环境不稳定
不同于单体应用的部署,微服务应用部署存在多机房、多配置的特点。一套全链路联调环境可能涉及几十个服务的部署,那么其中一个服务部署出现问题(服务器宕机、网络问题、配置错误等),可能会导致整条业务链路响应失败。理论上,环境稳定性和部署服务的数量成反比,这也是微服务架构下需要“环境治理”的原因。
当然,单体应用下也存在环境问题不稳定影响自动化用例的情况,而微服务架构下这种情况更甚!
服务依赖错综复杂
正如上文反复提到的,微服务架构下,不存在完全属于“孤岛”的服务,服务之间是存在依赖关系的。Java项目中一般以pom中引入其他服务的jar包方式构成依赖关系,如果需要升级依赖的jar包版本(主动升级/被动升级),就要注意下原来的契约关系是否有变化。
而在进行测试的过程,我们往往先mock掉依赖的服务,等保障域内质量OK之后,再进行和其他域联调测试。因此,项目进行前需要创建大量mock服务。
链路联调阶段,需要保证各域服务都ready,但是往往事与愿违,服务都有依赖的第三方接口,在自动化测试这些服务的时候都需要去了解业务方系统的接口、DB等。
下面分析几个场景
场景01.
(主动/被动)升级服务依赖jar包版本,如果服务自身没有发现能力,则存在变更风险。
曾经参加过一个项目,要求我服务的域升级下jar包,以配合上游需求要求。升级后全链路测试没什么问题,用例success。但是域内自动化有报错,发现jar包升级没做好向下兼容,故出错。
场景02.
有一条链路:服务A-服务B-服务C
服务A接口扩展字段新增业务标识信息经过服务B透传给给服务C使用。假设服务B对扩展字段字段长度有限制,那么服务A新增业务标识则存在风险。
很多同学遇到过类似的项目,既自己负责的域不在项目的改动范围内,所以就没有太关注项目本身了。针对这个场景,如果服务B域内自动化用例没有长字段校验用例,则很可能全链路也发现不了,因为测试场景下有时候会把某域mock掉或者说上游造的测试数据不够多样性(毕竟全链路测试角度从业务出发)。
综上,我们要正确看待全链路测试,不能迷信于全链路测试,觉得全链路测试通过就没啥问题了。要知道,全链路测试更多从业务角度出发,不能覆盖所有潜在异常场景,二者可以相辅相成,但对于日常自动化回归,我认为做好域内测试自动化才是底盘,全链路自动化没什么必要!