写点什么

自动化测试基础设施(一)——为功能测试构建通用 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:1511327

评论

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

MES系统是什么?MES软件有什么用?

万界星空科技

制造业 生产管理系统 mes 万界星空科技 生产管理

大咖公开课 | AI自动化应用开发,让创意与效率并驾齐驱!

测试人

软件测试

macOS Sonoma 14.6.1 (23G93) 正式版发布,ISO、IPSW、PKG 下载

sysin

macos ISO Sonoma

聚焦OLAP性能提升,火山引擎ByteHouse发布六大场景方案

字节跳动数据平台

数据库 云原生 Clickhouse 数仓

和鲸科技CEO范向伟出席江苏省信息技术应用学会软件技术专委会学术年会,解读“AI+教育”创新实践

ModelWhale

人工智能 软件 信息技术 产学研

数据分析慢?火山引擎ByteHouse发布六大场景性能提升方案

字节跳动数据平台

数据库 云原生 OLAP 数仓

聚焦OLAP性能提升,火山引擎ByteHouse发布六大场景方案

字节跳动数据平台

数据库 大数据 云原生 Clickhouse 数仓

观测云产品更新 | 异常追踪、用户访问监测、链路、监控等

观测云

异常追踪

AI安全新纪元:智能体驱动的网络安全新范式

云起无垠

AI 智能体

告别Hugging Face模型下载难题:掌握高效下载策略,畅享无缝开发体验

汀丶人工智能

人工智能 大模型

休闲手棋游戏:大富翁 10 for Mac 中文原生版可联机

你的猪会飞吗

Mac游戏下载 Mac破解软件 Mac软件下载站

榜上有名!望繁信科技荣登2023中国最具商业潜力榜

望繁信科技

流程挖掘 流程智能 上海望繁信科技 中国现代企业服务

Embedding空间中的时序异常检测

百度Geek说

安全 异常检测

我叫小舞,跳舞的舞!新斗罗大陆游戏详细图文架设教程

echeverra

斗罗大陆

LED显示屏行业可突破的六大领域

Dylan

云计算 虚拟现实 LED显示屏 全彩LED显示屏 led显示屏厂家

macOS Ventura 13.6.9 (22G830) 正式版发布,ISO、IPSW、PKG 下载

sysin

macos ISO ventura

实战从零开始实现Raft|得物技术

得物技术

分布式 raft 企业号2024年7月PK榜

云图说|一图告诉你主机安全的运维效率如何提升超出预期

华为云开发者联盟

运维 主机安全 新版本 企业号 8 月 PK 榜 2024企业号8月pk

技术同学如何应对降薪裁员

老张

职场 裁员 认知 互联网裁员

如何保护您的 Angular 应用程序:API 调用的端到端加密

哦豁完蛋了

使用观测云构建业务的可观测性

观测云

可观测性 业务监控

危化品安全生产风险监测预警系统的构建与实施

天津汇柏科技有限公司

安全生产 安全生产平台

海外成品语聊交友软件APP(英语+阿拉伯语版本)相比定制研发,优势有哪些?

山东布谷科技胡月

源码搭建 语音直播源码 语音聊天APP源码 海外直播App开发 海外语聊APP

AI自动化应用开发,让创意与效率并驾齐驱!

霍格沃兹测试开发学社

高价值数据源于结构化和非结构化融合分析

AI数据云Relyt

数据仓库 数据湖 数据分析 非结构化数据 AI-ready Data Cloud

全国高校软件测试开发教学师资培训会圆满落幕

霍格沃兹测试开发学社

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