写点什么

自动化测试基础设施(一)——为功能测试构建通用 mock server 系统

  • 2013-05-18
  • 本文字数:3371 字

    阅读完需:约 11 分钟

mock 在单元测试中已经众所周知。现今我们有各种功能强大而又好用的 mock 框架,可以很方便的解除单元测试中各种依赖,这大大的降低了编写单元测试的难度。而测试驱动开发(TDD)更进一步将 mock 作为一种设计手段,来辅助识别出元素之间交互的接口和职责。

那么在功能测试 (这里提到的功能测试指的是用户级测试) 这个层次,是否有必要使用 mock 呢?如果有必要又将如何构建呢?或者说是否有可能像单元测试中那样构建一个通用的 mock server 系统呢?本文将根据我的实践经历,向大家介绍一个通用 mock server 系统的主要组成部分以及设计思路。

Why

现今的业务系统很少孤立存在,它们或多或少需要使用兄弟团队或是其他公司提供的服务,这为我们的联调和测试造成了麻烦。对于这种情况,我们常见的解决方案是搭建一个临时的 server,模拟那些服务,提供数据进行联调和测试。这就是 mock server 的雏形。一般来讲,搭建这种 mock server 系统比较简单,不过它的功能也比较简单,而且往往需要针对不同的接口重复开发。那有没有可能像单元测试中使用的 mock 框架那样构建一个通用的 mock server 系统呢?

How

观察单元测试中的 mock 框架,我们会发现一般使用 mock 的流程是:

复制代码
init mock // 创建 mock 对象
config mock // 设置 mock 期望
setup mock // 将 mock 对象设置给被测对象
call // 调用被测接口,被测接口里的代码会调用 mock 对象
verify // 验证
拿 mockito 举例:
User expected = new User(“admin”, “12345”);
//init
UserDAO dao = mock(UserDAO.class);
//config
when(dao.findByName(“admin”)).thenReturn(expected);
//setup
UserService service = new UserService(dao);
//call
User actual = service.login(“admin”, “12345”);
//verify or assert

借鉴这种做法,我么就可以构建一个简单的 mock server 系统,接下来的内容中,我们会在这个 mock server 的基础上演化出比较完善的版本。

版本 1(简单的模拟值)

假设我们需要 mock 的是 HTTP 接口。我们的 mock server 提供一个配置接口 (对应着上面的 config mock 步骤),测试运行之前调用配置接口将需要 mock 的 HTTP 接口 URL 以及需要返回的值传递过去,mock server 内部建立 url 到返回值的关联 (这里就类似存在一个哈希表一样)。Mock server 还提供另外一个接口供被测系统调用。这是一个通用的接口,所有原先指向真实服务的地址全部被指向到该接口 (可以通过修改配置或修改系统 hosts 文件)。当该接口被调用时会寻找刚才建立的 url 到返回值的关联,并将 mock 的值返回。这样一个非常简单的 mock server 就构建出来了,对于一些简单的联调场景基本够用。这个时候我们的 mock server 的原理图如下面所示:

版本 2(提供调用参数的查询)

有了第一版的 mock server,对一些只需要模拟值的场景是够用了。但是,mock 的作用仅限于此么?想想单元测试中的 mock。在单元测试中 mock 框架除了能够为被测系统构建输入值外,还能捕获到被测程序传出的值,然后对这些值进行校验。举一个实际的例子:在我们的系统中经常需要向用户发送短信,为了对发送的短信功能以及短信内容进行验证,在没有 mock 之前我们可能真的需要向真实手机发送短信,然后验证。这不仅降低了测试效率,也增加了不少不可控因素。为此我给 mock server 添加第三个接口:query 接口。在被测系统调用 mock 接口时,mock 会记录下被测系统传递给 mock 接口的参数值,然后测试中可以调用 query 接口查询到记录的值,在测试中可以对其断言,而且这里记录下的调用记录还可以作为日志提供出来,提高系统的诊断能力。这样我们的 mock server 的结构就变成:

版本 3(可以根据参数模拟)

现在我们的 mock server 已经可以提供类似 verify 的功能了,但实际上它还不能算一个真正的 mock。它也不能处理哪怕稍微复杂一点的情况。在实际中,我们经常需要针对不同的参数返回不同的值。举个简单的例子:我们 mock 一个支付接口,对于订单号 123 我们期望支付成功,对于订单 234 期望支付失败。这就引入了我的 mock server 的两个核心组件:extractor 和 matcher。Extractor 组件主要用于从调用的参数上提取出参数值,然后转换成 key/value 的格式提供给后续的环节使用;因为请求的参数格式多种多样 (json,xml 等),extractor 为此提供了统一的接口。

Matcher 组件的作用是在拿到 extractor 传递过来的 key/value 值后利用一些匹配器匹配到具体设置的期望上,所有匹配到的调用会返回对应的值。也就是说 mock server 内部不再是简单的映射了。后面再介绍 DSL 部分的时候会介绍 matcher 使用的语法。这样我们的 mock server 结构就演化成下图:

版本 4(提供多种协议的支持)

估计有人在抱怨,说了这么多这个 mock server 还只能 mock HTTP 接口啊,我们的系统中存在 HTTP 接口,RPC 接口,SMTP 接口等等。这是 mock server 中协议组件的职责。协议组件是 mock server 的入口,它提供多种协议的服务,并且解析出协议包数据,然后将数据交给 extractor 组件;除此之外,协议组件在收到上层的返回值后,会按照协议的格式返回给被测系统 。利用一些开源的类库,我们可以很容易对一些通用协议提供支持,但对一些私有的二进制协议如果没有现成的库支持,要重新开发成本很大,不过我们可以从客户端来解决这个问题,这在后续的文章中会有介绍。

版本 5(模拟行为)

基本上一个功能还算完善的 mock server 成型了。但这就够了么?对于要模拟各种场景的测试还远远不够。我们很多接口有回调的功能,我们通常还需要模拟接口超时的情况,而对于一些支付相关的接口经常需要对参数进行加密解密,而且这些情况都需要是可配置的。有没有发现,前面我们介绍的所有实际上都是 mock 值。也就是我们设置一些值,然后调用的时候将值返回。但是很多时候我们不仅需要 mock 值,更要 mock 行为。这样我们有了 mock server 中最核心的组件:命令执行引擎 (好牛的名字,其实就那样)。在设置 mock 的时候我们不再是设置一个值,而是设置一个预定义命令组合成的流水线 (即按照类似下面 xml 的配置一步一步执行,并且可以将上一步的执行结果传递给下一步):

复制代码
<delay>1000</delay>
<callback url=http://localhost/callback.do>{“ret”:”true”}</callback>
<return>{“ret”:”true”}</return>

上面的流水线被命令执行引擎解析执行后就是按顺序执行对应的 DelayCommand, CallbackCommand 以及 ReturnCommand 命令了,具体命令就不介绍了。采取这种方式给我们 mock server 带来了很大的灵活性:只需要简单的扩展一个子命令,就可以扩充 mock server 的行为。比如 mock 某网关接口时需要使用 MD5 加密,只需要扩展一个 MD5Command(下面代码中的 $result 表示前一步骤 <md 5 /> 加密后的结果):

复制代码
<md5 />
<return>$result</return>

DSL

现在我们的 mock 不仅可以 mock 值了,对于各种行为的模拟也得心应手。但是要使用方便,还要提供便于使用的接口。Mock server 提供两类接口:针对自动化测试的 DSL,以及针对手工测试使用的管理界面。这里主要介绍这种 DSL(因为我们的测试用例是使用 xml 编写,转换成编程语言也很容易):

复制代码
<mock service=”http:/test.json” matcher=”hasKey($param.orderNo)”>
<delay>1000</delay>
<md5 />
<return>$result</result>
</mock>

service 是对被 mock 的服务的描述,比如对于 SMTP,我们可以这样定义: service=“smtp:9000”。这个表示在 9000 端口上监听 smtp 协议。而 matcher 即前面介绍的 matcher 组件所使用的各种匹配器,用于匹配被测系统调用 mock server 时传递的数据。比如上面的例子表示的就是如果被测系统调用 http 接口 /ticket.jsp,并且参数里包含 orderNo 则延迟 1 秒钟,然后返回一个 json 值 。

总结

前面几节介绍了一个比较完善的通用 mock server 从简到繁演化的设计思路,希望可以为想要构建类似设施的读者提供一个参照。

这个 mock 系统包含两个主要部分:mock admin 和 mock server。Mock admin 是管理界面,主要提供监控 (可以在界面上实时看到被测系统与 mock server 交互) 以及手工测试时的配置界面。 Mock server 即前面介绍的主体,其架构如上图所示。Mock server 包含几个核心组件:协议、extractor、matcher、命令执行引擎、存储 (即 mock server 中使用的各种数据的存储)。Mock server 提供三类接口:配置、被 mock 接口 (各种服务,通过协议组件提供)、查询。

2013-05-18 05:1511144

评论

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

【LeetCode】火柴拼正方形Java题解

Albert

LeetCode 6月月更

RxJS系列01:响应式编程与异步

代码与野兽

6月月更

6 月直播 7 场干货全剧透!今天:飞腾CPU调优原理及方法 | 第 19 期

OpenAnolis小助手

cpu 直播 sig 龙蜥大讲堂 飞腾

CPU利用率从10%提升至60%:中型企业云原生成本优化实战指南

星汉未来

运维 云原生 IT成本 星汉未来 FinOps

ironSource LevelPlay 聚合平台,现已适配应用开发框架工具包 Flutter

极客天地

大数据培训如何使用DPM规划用户画像

@零度

大数据 dpm

相约龙蜥,开源一“夏”!2022编程之夏ASoC开始报名了

OpenAnolis小助手

阿里巴巴 开源项目 龙蜥社区 高校学生 技术项目

招聘 | 上班轰趴,下班狼人杀,天天招人,怕是要发!

Alluxio

面试 程序员人生 招聘 互联网热点 Alluxio

为什么你的网站需要搭建在线帮助中心?

小炮

2022 支付宝五福 |“联机版”打年兽背后的网络技术 RTMS

阿里巴巴终端技术

客户端 网络技术 网络通信

【高并发】你知道吗?大家都在使用Redisson实现分布式锁了!!

冰河

并发编程 多线程 高并发 异步编程 6月月更

Jetpack Composes 入门

坚果

6月月更

运维领域告警智能定级原理探索(含详细实验报告)

云智慧AIOps社区

运维 安全 监控 告警

《数字经济全景白皮书》证券期货用户数字化篇 重磅发布

易观分析

证券 期货

java培训 | 零基础学习java开发的学习方法有哪些

@零度

Java 学习方法

WASM VS EVM,波卡的选择预示了公链未来

One Block Community

区块链 公链 波卡生态

定档615 | 数字化基础软件自主创新分享周即将来袭,点击获取“通关密钥”!

网易数帆

大数据 云原生 基础软件 数字化转型 自主创新

【直播回顾】参与ArkUI,共建OpenHarmony繁荣生态

OpenHarmony开发者

Open Harmony

Docker下RabbitMQ延时队列实战两部曲之一:极速体验

程序员欣宸

RabbitMQ 5月月更 RabbtiMQ延时队列

为企业业务流程提速的BPM

力软低代码开发平台

墨天轮访谈 | SelectDB 衣国垒:Apache Doris(incubating)1.0版本特性解析与未来规划

墨天轮

数据库 Apaache Doris 国产数据库

做数据时代的加油站,ShardingSphere 为易车数据库架构演进提供新动力

SphereEx

Apache 数据库 开源 ShardingSphere SphereEx

幸运哈希算法竞猜游戏开发特点分析(成熟方案)

开发微hkkf5566

如何撰写数据中台蓝图方案

agileai

数据中台 企业服务总线 主数据平台 数据分析平台 蓝图方案

各国儿童节时间是不一样的

清林情报分析师

数据可视化 知识图谱 儿童节

“东数西算”与“双碳”双驱力叠加,新华三争当“全能型选手”

BeeWorks

深度操作系统20.6正式发布!

深度操作系统

开源 深度操作系统 deepin20.6 新版本 深度

2022年4月线上终端药品增长迅猛,市场政策合规进程加快

易观分析

医药类

成本节省 50%,10 人团队使用函数计算开发 wolai 在线文档应用

Serverless Devs

Serverless wolai

英特尔计划建造浸没式实验室,帮助高功率芯片快速降温

BeeWorks

移动端异构运算技术-GPU OpenCL编程(进阶篇)

百度Geek说

自动化测试基础设施(一)——为功能测试构建通用mock server系统_软件工程_余昭辉_InfoQ精选文章