HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

苏宁 MOCK 测试桩服务建设实践

  • 2018-08-20
  • 本文字数:5148 字

    阅读完需:约 17 分钟

前言   

2018 年苏宁易购提出了智慧零售大开发战略,今年将新开 5000 家门店,到 2020 年,线下门店总数达 2 万家。半年来,以急速推进的大开发战略高超迭起,店面实现从城市到县镇市场全面覆盖,使得消费者在任何时间、任何地点、任何服务的需求都可以得到满足。

这样的发展速度对苏宁的 IT 技术提出了更高的要求,其中一个重要的环节就是加快软件版本的上线步伐,伴随着软件的上线必然存在巨大的测试压力,在敏捷过程中,苏宁测试遇到了如下困境:

  1. 依赖方不可用,测试人员无法提前介入测试;
  2. 数据构造,复杂的场景或者特殊的数据,无法很快生成,导致场景无法覆盖;
  3. 异常模拟;
  4. 外部系统不可用,或者没有对应的测试环境,或者需要现金交易;
  5. 压测时,依赖方性能较差,无法保证本系统性能最优;全链路压测时,无法限定链路范围;

为了提高生产效率和测试覆盖率,苏宁蛙测平台上线全场景 Mock 桩服务解决方案,支持 HTTP、ESB、RPC 等协议 Mock,支持同步、异步以及回调场景等功能,成功解决测试人员、开发人员在测试和研发过程中,数据构造、环境依赖等痛点,大大提高了生产效率,提高测试场景的覆盖率,保障了业务版本上线的质量。目前蛙测 Mock 服务应用于苏宁 100+ 中台、后台系统,服务了 1000+ 万次桩服务调用,在苏宁各个测试产品线得到了广泛的应用。具备的能力如下:

实践过程及应用效果

第一阶段:Mock1.0 从无到有过程

当初,苏宁并没有一套通用的 MOCK 服务能力,各个业务线基本是由开发人员,在应用代码中,植入 Mock 逻辑,由测试人员在应用外部统一针对特定接口进行预埋桩响应内容,这样的方案给开发和测试带来了很大的工作量,开发人员需要在版本迭代过程中,不断维护 Mock 逻辑,同时也污染了应用代码,很容易把 Mock 逻辑发布到生产坏境,增加上线的风险。所以,迫切的需要一套通用的 Mock 服务能力。基于这样的问题,苏宁蛙测服务平台,通过收集各个产品线 Mock 需求、分析,开始从 0 到 1 建设一站式 Mock 服务能力,实现代码无侵入式的通用 Mock 服务桩,也就是 Mock1.0 版本,整体思路是与中间件打通,组件识别 Mock 的标识,将请求路由到 MockService 上,实现千人千面的 Mock 服务:

正常请求

而由测试工具发起的请求(HTTP、ESB、RPC 等),首先测试人员会在本地预埋 Mock 响应内容,同时启动本地 MockService,在发起 Mock 请求时会生成的 Mock 标识,Mock 请求到达被测系统 A 时,相应组件会识别此 Mock 标识,将依赖方的请求转发到 MockService 上,大致思路如下:

Mock 请求

Mock 标识如何传递:

  1. RPC 类型:内部 Java 远程调用框架 RSF,在测试工具模拟服务消费方,发起 RSF 请求时,会附带本次请求中需要 Mock 的后端依赖方,以 Attachement 方式附带到 RSF 服务方,在服务方应用中,RSF 组件会进行识别、路由,RSF 中间件请求完成后,进行 Mock 信息清理;
  2. HTTP/ESB 类型:被测应用在打包或者 CD 发布时,手动或者自动在 web.xml 中配置中增加 Mock 的 filter 过滤器,在 doFileter 方法中,如果识别到 HTTP 请求头中包含 Mock 标识,则将 Mock 信息设置到中间件中,在中间件发起依赖方 HTTP 请求时,进行 Mock 识别、转发,请求结束后,清理本次请求的 Mock 信息;

测试工具如何埋桩

一次 RPC 的调用,可能涉及多个后端依赖系统服务调用,所以,在工具脚本设计时,增加了步骤 Group 概念。把本次一次调用过程中,需要 Mock 的调用,放在一个 Group 下,在发起请求时,把 Group 下的 Mock 步骤,打成多个 Mock flag 标识,供 RPC 组件中 Mock 识别模块识别,交互如下:

在 MockService 服务上,还支持匹配规则,根据匹配规则,响应不同内容。

在 Mock1.0 服务中,仅支持 RPC、HTTP、ESB 同步类型、基于单次请求级别的 Mock 调用,测试人员在本地用测试工具进行发起请求,每个测试工具都作为一个独立的 MockService 存在,达到互不干扰、千人千面的效果,同时业务方系统无需植入 Mock 代码,即可支持 Mock 能力,大大减少开发工作量和发布上线风险。

随着 Mock 功能深入开展,基于请求级别的 Mock 还远远不能完全满足业务测试场景,尤其是后台系统,测试人员在实际使用过程中,又遇到如下困难:

  1. 多线程、Job 等异步方式发起后端依赖方请求,尤其应用自己实现的多线程逻辑时,请求的调用链路会断开,导致 Mock 标识无法传递;
  2. 被测应用的一次调用过程,往后端系统同一个接口,发起多次不同参数的请求,无法得到不同的 Mock 响应;
  3. 实际测试场景中,存在回调过程,无法模拟;
  4. 请求从 UI 层面发起时,无法生成 Mock 标识;

为了解决测试的痛点,提高测试覆盖率,蛙测平台将 Mock1.0 进行功能扩展,推出了全局桩、UI 桩、回调桩等功能,也就是 Mock2.0 版本。

第二阶段:Mock2.0 从局部到全面过程

在 Mock1.0 版本中,仅支持请求级别的 Mock 功能,而在 Mock2.0 版本中,Mock 能力将从请求级扩展到全局桩、UI 桩、回调桩等全面桩,解决测试过程中,所涉及的 Mock 需求。

全局桩

全局桩功能是为了解决异步、多线程等测试场景,整体思路是:测试人员事先一次性的将需要 Mock 的依赖方接口信息,刷入被测系统 JVM 内存中,这些 MOCK 信息,全局生效,当请求中没有附带 Mock 标识时(请求可能由页面触发、也能由其他测试工具触发),被 Mock 的后方接口,一律走全局桩服务,当请求中附带 Mock 标识时,请求级 Mock 优先级高于全局桩 Mock。

UI 桩

UI 桩主要应用于是分层测试设计中,通过分层、解耦,可以简化问题,针对有明确分层设计的系统,在层与层之间验证接口的正确性。比如:Web、APP UI 层面,可以适当介入 Mock,将关键接口 Mock 掉,达到 UI 验证的目的,而后端接口,通过接口方式进行场景验证,从而达到分层测试目的。UI 桩设计思路如下:

测试工具可以自动将本地浏览器代理、手机代理设置为 Proxy 服务地址,同时,根据规则,监听前后交互请求,测试人员可以选择录制生成自动化脚本,还可以根据规则篡改、响应等等,达到前后分离测试目的,还能屏蔽后端服务或者接口,对边界值、等价类划分等数据进行模拟,提高测试场景覆盖。

测试工具提供简单的 GUI 操作,具体如下:

启动代理

生成步骤

埋桩

回调桩

在实际系统交互中,还存在这样的场景:后方依赖服务响应比较慢,在高并发场景下,调用方会积压大量的线程阻塞等待依赖方的返回结果,导致调用方资源被耗尽,产生严重后果,为了解决这种场景,业务方一般采用异步回调方式来解决。为了模拟异步回调测试场景,Mock 能力也扩展了回调功能,模拟后方系统结果返回、延迟回调等场景,从而达到测试目的。

第三阶段:从自动化到压测挡板过程

从第一阶段的请求级桩到全局桩,桩的服务能力不断增强,不断满足测试产品线各类业务场景,主要针对功能的验证,模拟依赖方的返回,并结合自动化工具,固化成脚本,达到复用的目的。但在性能测试过程中,期望对 Mock 还需具备压测挡板的能力,问题如下:

  1. 在跨系统的性能测试中,由于客观因素的限制,如:测试资源有限、后端系统不具备压测条件、后端系统性能不达标等,导致无法线下压测被测系统性能;
  2. 全链路压测过程中,无法屏蔽外部依赖系统和限定链路范围;
  3. 线下压测过程中,很难模拟在后端应用不同性能下,比如:延迟设置 0.5s、1s 甚至 2s 的不同延迟,考察被测应用在不同的延迟情况下的性能表现。

为了解决以上压测过程中问题,蛙测推出了基于热插拔方式压测挡板服务,主要解决了压测过程中,模拟依赖应用性能,比如:TPS、响应延迟等,具备能力如下:

  • 支持热插拔,随时可以终止 MockFilter 服务,提高了系统对灾难的及时恢复能力、扩展性和灵活性;
  • 支持消费端挡板,桩信息一次性刷入被测应用 jvm 中,被 Mock 的后端服务,直接从消费端内存中直接获取并返回,模拟延迟等,此 Mock 请求直接从被测应用的服务器内拿 Mock 响应;
  • 支持服务端挡板,桩服务由蛙测平台额外独立提供,根据用户设定的性能 TPS 指标,动态计算需要多少 Mock 服务线程以及多少台 Mock 服务节点,并把响应的 Mock 信息一次性刷入到 Mock 服务器中,供本次压测使用,此 Mock 请求从被测应用服务器外部拿 Mock 响应;

为什么要区分消费端挡板和服务端挡板呢?主要是在实际应用中,尤其生产环境的压测,并没有那么多的 Mock 服务器资源供挡板调用,而消费端挡板恰恰解决了这一问题,充分利用被压应用服务器资源,压测预热前,一次性刷入需要 Mock 的后端应用服务,压测过程中,通过各个中间件进行 MockFilter,决定后端调用是 Mock 调用还是真实调用,是消费端 Mock 还是服务端 Mock。

消费端挡板整体思路

服务端挡板整体思路:

蛙测挡板创建

消费端 VS 服务端挡板压测结果对比

  • 压测目的:消费端挡板与服务端挡板性能对比
  • 机器 4C 8G
  • 场景:被 Mock 系统模拟桩数 1 万条

从压测对比中,得出结论:消费端挡板性能表现远远的高于服务端挡板,但相应的对于服务端资源消耗占比较高。针对以上数据对比,并结合实际业务场景压测需求,可择优选择合适的挡板方案。

结语   

蛙测的 Mock 服务能力从最初的请求级、千人千面的 Mock 到全局桩能力,从手工测试到自动化测试再到压测挡板,不断的探索、提升测试过程中的效能。未来,我们还会在字节码层面进行线上录制,转化成自动化脚本,回放到测试环境,Mock 掉必要的依赖调用等,达到线上录制回放的目的,在测试技术方向,蛙测团队将会继续努力探索,永不停歇!

作者简介

程派峰,苏宁易购测试平台高级技术经理,2013 年加入苏宁,一直从事测试工具与平台的研发工作。具备广泛的技术视野和很强的技术前瞻性,了解新技术、新趋势,擅长自动化测试技术创新。对各种开源框架有了解,并具备良好的落地实践,目前专注于工程效能及质量提升工作。

感谢张婵对本文的审校。

2018-08-20 18:103721

评论 1 条评论

发布
暂无评论
发现更多内容

架构师训练营 第4周作业

Glowry

极客大学架构师训练营

一张PDF了解JDK9 GC调优秘籍-附PDF下载

程序那些事

性能调优 GC JDK9 cheatsheet 秘籍

架构师训练营作业-20200627

caibird1984

极客大学架构师训练营

Python多重继承问题之MRO和C3算法

王坤祥

Python MRO C3算法 多继承

使用 Python 制作酷炫多彩的 Jenkins 插件词云图

donghui

jenkins wordcloud

计算机操作系统基础(七)---作业管理之死锁

书旅

php laravel 线程 操作系统 进程

架构设计之常识篇

魔曦

架构师 极客大学架构师训练营

架构师训练营第三周作业

陈靓-哲露

架构师训练营:第四周作业

zcj

极客大学架构师训练营

「架构师训练营」第 4 周 学习总结

guoguo 👻

极客大学架构师训练营

消息队列(四)如何处理消息丢失的问题?

奈何花开

Java MQ 消息队列

架构师是怎样炼成的 04-1互联网分布式系统架构演化

闷骚程序员

极客大学架构师训练营

架构师训练营第四周作业

Melo

【6月】本月读书学到了什么

Neco.W

读书感悟 阅读量

前端存储除了 localStorage 还有啥

阿宝哥

Java 大前端 存储

第四周总结

芒夏

极客大学架构师训练营

第四周作业

芒夏

极客大学架构师训练营

架构师训练营第四周作业

W_T

聊聊Hystrix中的命令模式

老胡爱分享

Java 面试 设计模式 命令模式

架构师训练营总结-20200627

caibird1984

极客大学架构师训练营

极客时间架构师训练营 - week4 - 作业 1

jjn0703

极客大学架构师训练营

漫画:15张图,帮你看懂布隆算法

Java小咖秀

面试 算法 布隆过滤器

漫画:对象是如何被找到的?句柄 OR 直接指针?

王磊

Java 面试

戴尔Latitude 9510 雅典娜计划标准的英特尔移动超能版笔记本

最新动态

极客大学算法训练营第一课

落曦

理解了 1+2 的过程,你就理解了Java虚拟机

侯树成

JVM JVM原理

架构师训练营 第4周学习总结

Glowry

极客大学架构师训练营

程序员面试与 HR 谈薪资技巧

张小方

程序员 面试 offer 年终奖 月薪

时间管理的本质到底是什么?

非著名程序员

程序员 提升认知 时间管理

消息队列(五)如何保证消息的顺序性?

奈何花开

Java MQ 消息队列

Golang中的Interface(接口),全面解析

Eriol

接口 interface Go 语言

苏宁MOCK测试桩服务建设实践_软件工程_程派峰_InfoQ精选文章