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

发表于:2013-5-24 13:06

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:余昭辉    来源:51Testing软件测试网采编

  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结构就演化成下图:

21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号