干货 | 携程微服务架构下的测试浅谈
作者简介
施赛花,携程机票BU测试工程师,主要负责携程机票聚合层服务的测试,以及自动化工具的开发。善于研究新技术,并转用于实践,提升测试工作效率。
在现在这个互联网时代,多变的市场环境以及日益增长的客户需求,加速了产品的迭代和更新。传统的单体式应用已经因跟不上发展的步伐而逐渐退出历史的舞台,取而代之的是SOA的问世。
SOA的出现使系统架构发生了跳跃式的转变,它提出了面向服务的设计思想。而现今流行的微服务架构,和SOA虽是一脉相承,但不再强调传统SOA架构里的ESB(企业服务总线)。
使用微服务架构可以将系统划分成更细粒度的服务,每个微小服务实现单一业务功能,且可以根据自身特点选择更适用的编程语言和技术。每个微服务可以由不同的团队独立完成开发,互不影响,加速了产品的推出和迭代。
夸张一点说,如果将整个软件系统比作宇宙的话,那每个微服务就好比行星,它可以独立的运行在自己的进程中。各服务之间通过网络通信,看似独立,却又因业务联系关联在了一起,就像各个行星之间有着引力等物质将它们紧紧关联。一系列独立运行的微服务就共同构建起了整个系统。
以传统建筑行业为例,项目的完成需要设计院、施工方和监理单位协同合作。类比到软件系统中,架构师、开发和测试也是缺一不可。微服务架构下,更要求采用的测试策略能够为服务内部的完整性,以及每个服务之间的交互,提供全面的测试覆盖。
相比于常见的UI测试层、接口测试层、单元测试层,三层测试金字塔,在微服务架构,这个分类可以被扩展为5类。
下面将逐一介绍在微服务架构中主要采用的测试类型:
单元测试
单元测试是针对代码单元的测试,通常只测试一个函数和方法调用,验证其运行结果是否符合预期,是对代码质量最快速的反馈。高覆盖率、高质量的单元测试是保障代码质量的第一道保护伞。在掌握TDD(Test-Driven Design,测试驱动开发)的前提下,单元测试更是对代码重构起到了非常关键的作用。
集成测试
虽然单独测试模块非常重要,但是测试各个模块之间交互是否正常,同样也占据了重要的地位。在微服务架构下,集成测试的目的是把一些子模块组合在一起,测试其作为子系统是否存在缺陷,检查模块之间的通信和交互是否通畅且准确,是否以预期的方式协作。
组件测试
在微服务架构中,组件实际上就代表着微服务本身,所以组件测试就是检查服务内部功能实现是否完整,内部逻辑是否正确,异常处理是否正常等。
契约测试
契约测试称之为消费者驱动的契约(Consumer-Driven Contracts,简称CDC)测试。契约测试是为了测试服务之间连接的正确性,测试服务能否符合契约预期,即是否能真正满足服务消费者的需求。
端到端测试
端到端测试是从UI层开始执行,目的是检查整个软件系统是否符合用户的预期需求。一个常规页面功能展示的背后往往涉及多个服务,所以运行端到端测试需要部署多个服务。这样的测试能够达到更广的覆盖面,但是也面临测试不稳定,定位问题难等问题。
在微服务架构下,前端及后端各微服务之间都是分开研发及测试。保证每个微服务本身的质量成了测试中至关重要的一环。要想楼房造的高而稳,那基础必须扎实。微服务就好比那基石,高质量的微服务,是保障软件系统整体质量的关键。
相较于端到端测试在敏捷开发中的维护成本,服务在迭代研发过程中,和UI相比变化相对少,所以自动化更易维护,且能在迭代中不断复用。而且,服务测试自动化受外界因素的影响较少,不会受浏览器、手机型号及系统版本等影响。
微服务架构带来了便利,随之也给测试工作增加了难度和新的挑战。测试人员必须跟上时代的步伐,调整自己的测试方法和工具。
怎样模拟多样的上层数据以及稳定的下层服务,高效、高覆盖的完成对服务的测试。此时,携程基于微服务架构的自动化比对工具就应运而生了。
该比对工具是以生产Log作为测试数据源,通过Mock、缓存等实现生产流量在测试环境的回放,以达到对服务进行全面测试的目的。
1)缩减测试数据维护成本、增加测试覆盖度
因是对服务的测试,首先要做的就是模拟上层应用或系统调用被测服务。常规服务测试自动化中,测试数据都是由自动化来完成构建,痛点:数据维护成本高,Case量级偏少。
解决方案:
拉取生产的Log数据作为数据源,这样原来5%左右测试数据的维护成本就缩减为了0%。数据每天定时拉取,增加了数据的新鲜度。且拉取的数据量大,这样就能保障数据的多样性,丰富的测试场景,以达到增加覆盖度的目的。
2)测试用例的持续运行成功
因测试环境的不稳定性,以及测试环境数据的缺失,且对于下层服务返回数据的强依赖性,做到Case持续运行成功并不是一件容易的事。
解决方案:
通过实现Mock,摆脱对底层服务的依赖,且能高效还原当前Case在生产环境的测试场景。
3)实现对被测服务所有输入输出流的验证
很多时候被测试的服务内部需要去调用其他服务,且有非常复杂的逻辑判断,对调用其他服务这块中间输出流的验证也是非常重要的,所以常规只对服务返回结果的验证远远不够。
解决方案:
实现对被测试服务所有输入输出流的比对验证。
比对工具中最关键的是实现两个服务:
比对服务:负责测试数据的拉取、被测服务的调用以及最后的比对;
Mock服务:负责被测服务需要的返回结果的高效匹配,以及对调用其他服务请求报文的收集及缓存。
比对工具工作流图:
仿真生产流量
通过实现多线程,对生产上高QPS的服务,能够高效还原生产流量场景,并且通过模拟生产高并发时被测服务的负载量,使原本还有藏身之所的Bug更无所遁形。同时,每次运行Case的时间也有了量级上了缩减。
灵活Mock下层服务
以携程机票一个聚合层服务为例,它需要调用超过30个下层服务,常规测试用的打桩服务需要对指定下层服务进行预设返回,在多线程的情况下,这种方式匹配效率较低且容易出错。我们Mock服务中对打桩功能进行了改良,不仅摆脱对指定服务的Mock,并能快速准确的匹配返回结果。
多种比对方式
工具除支持两个测试环境进行比对外,更支持直接与生产数据比对。不同的比对方式,满足更多的测试需求,且对于被测服务中已知有变化的节点,也支持除外不比较,大大缩减测试结果的分析时间。
技术的发展不会停步,学习的脚步不会停止。在微服务架构下,除了对微服务技术本身的研究外,对更适用于微服务架构测试的探究,是每个测试人未来努力发展的方向。
【推荐阅读】