花椒接口Mock方案


奇技指南

Mock是指在测试过程中,对于一些不容易构造/获取的对象,创建一个Mock对象来模拟对象的行为。本文主要讲述Web接口的Mock。

本文来自公众号花椒技术


什么是Mock?

Mock是指在测试过程中,对于一些不容易构造/获取的对象,创建一个Mock对象来模拟对象的行为。早期Mock多被用于单元测试/接口测试中,被测试对象依赖其他对象,且这些对象的构造复杂、耗时或者根本无法构造(未交付), 对于单个测试对象,假定其依赖对象的逻辑正确,我们只需要保证测试模块内部逻辑的质量即可。本文主要讲述Web接口的Mock。



接口Mock用处?

在实际的软件开发过程中,我们的链路往往是:服务业务A->服务业务B->客户端/前端->测试,整个开发周期里,业务B的人依赖业务A才能联调提测,客户端/前端依赖B的接口有数据后才能开发新的功能,Mock很好缩短了这个过程中等待的时间。

1. 客户端/前端开发联调前置,现今移动端的app多依赖服务端接口的返回来开发app的页面,在接口未开发完成的情况下,需要等待接口的数据来进行开发,这时候完善的的接口Mock服务能大大缩短开发联调等待时间。

2. 接口集成测试,部分依赖服务未完成前,利用Mock完成本身的接口开发/测试

3. 复杂的场景模拟,复现验证bug的时候,需要先准备比较复杂的数据场景,才能复现一个bug,此时,Mock的定制返回,节省了大量数据准备的时间,直接可复现和验证bug

4. 测试时,异常场景的模拟,如长字符串,负数,异常返回等


花椒的Mock方案

说了这么多,我们来说说花椒的接口Mock方案。传统的接口Mock服务弊端有:

  1. 需要绑定接口请求的业务服务到指定的Mock服务,这样需要wifi的host不停更改,或本机的host不停更改,来切换正常环境和Mock环境

  2. 绑定host因为是整个域名绑定到Mock服务,如果其他接口没有Mock会导致很多接口不可用,而走不到想走的场景,且多人公用wifi的情况下,会互相影响

  3. 不同的用户对同一接口的请求,期望的返回不一样,无法对用户定制化,也即同时只能满足一个开发或测试人员的Mock需求

  4. 传统的Mock服务大多采用文件编辑Mock数据,不易编辑管理

考虑到上述弊端,我们的接口Mock服务,设计的初衷有以下几点:

  1. 如何让客户端/前端开发人员简单易用,不需要太多环境的设置,保证用户能在正式环境和Mock环境之间切换

  2. 如何支持多用户同时使用,且Mock数据不一样的需求

  3. 花椒的部分服务是有加解密的,返回的数据是一堆加密串,如何更方便的编辑管理Mock返回数据

花椒的接口Mock方案, 主要是采用业务服务器跳转 + Mock服务 + 后台管理,同时支持传统的Mock服务的使用方式。

640?wx_fmt=jpeg
Mock1

主要有如下三部分组成:

Mock后台

Mock后台是整个Mock服务的配置中心, 用户在后台定制自己的接口Mock数据,配置需要跳转的用户及接口。开发框架用的是springboot + mybatis + vue,前端页面和后端服务剥离,springboot提供操作数据库的接口给前端vue页面调用,主要文件目录一个vueMockController, 一个数据库操作文件MockMapper,文件目录非常简单,主要功能有:

1. 展示用户的所有Mock数据,支持根据作者查询,uri查询,模块查询

 1/按Uri查找数据 2@RequestMapping("findByUri") 3public RestResult findByUri(@RequestBody JSONObject request) throws Exception { 4    int offset = request.getIntValue("offset"); 5    String uri = request.getString("uri"); 6    uri = "%" + uri + "%"; 7    List<MockData> data = mapper.getMockDataByUri(uri, offset); 8    for (MockData one : data) { 9        one.decryptData();10    }11    int total = mapper.getMockDataByUriTotal(uri);12    return success(formatPageData(data, total, offset));13}

2. 支持新增,删除、编辑Mock数据功能,写入数据根据选择的平台ios/android,判断有无加密,有加密按各自的加密key加密后写requset和response数据到数据库

主要数据库信息如下, encrypt是否加密,platform(请求客户端iOS或Android),model为模块,uid为用户私有标识,request为请求参数(同时支持key=value的form数据,{“key”:“value”}的json数据),response为响应数据

 1TABLE `mock` ( 2  `id` bigint(20) NOT NULL AUTO_INCREMENT, 3  `uri` varchar(255) DEFAULT NULL, 4  `request` varchar(500) CHARACTER SET utf8mb4 DEFAULT NULL, 5  `response` text CHARACTER SET utf8mb4, 6  `statusCode` int(11) DEFAULT NULL, 7  `platform` varchar(20) CHARACTER SET utf8mb4 DEFAULT NULL, 8  `encrypt` tinyint(1) DEFAULT NULL COMMENT '0无 1经济 2底层', 9  `model` varchar(20) CHARACTER SET utf8mb4 DEFAULT NULL,10  `author` varchar(20) CHARACTER SET utf8mb4 DEFAULT NULL,11  `moduser` varchar(20) CHARACTER SET utf8mb4 DEFAULT NULL,12  `server` tinyint(1) unsigned DEFAULT NULL,13  `method` tinyint(1) unsigned DEFAULT NULL COMMENT '0Get 1Post',14  `uid` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL,15)

对应的页面展示如下,同时提供了加完数据后运行查看是否Mock成功的功能.

640?wx_fmt=jpeg
mock3

3. 获取业务服务器所有Mock配置,并展示,支持新增,编辑,修改后同步设置到业务服务器

640?wx_fmt=jpeg
mock2


Mock Service

Mock service是Mock请求/返回处理的中心模块,主要逻辑是获取跳转过来的用户请求,处理请求数据,根据不同的请求参数,查询数据库里的配置数据,修改response数据为Mock数据返回给用户。开发框架是基于git上开源项目Moco的二次开发, Moco在git上的开源地址https://github.com/dreamhead/moco, 是一个简单搭建模拟服务器的程序库/工具, 基于java开发的,Mock数据通过文件管理,使用方式很便捷简单,但由于本身花椒服务的特殊性,和考虑到可视化管理,我们对Moco进行了二次开发,主要改动方向:

1. Mock数据管理新增数据库存储管理方式, mybatis连接数据库,新增一个数据库操作MockMapper文件,新增一个service方法来处理数据库查询合并结果,具体的mybatis的配置如下:

 1<configuration> 2    <environments default="development"> 3        <environment id="development"> 4            <transactionManager type="JDBC" /> 5            <!-- 配置数据库连接信息 --> 6            <dataSource type="POOLED"> 7                <property name="driver" value="com.mysql.jdbc.Driver" /> 8                <property name="url" value="jdbc:mysql://10.14.*.*:port/db_name?useUnicode=true&characterEncoding=utf-8" /> 9                <property name="username" value="username" />10                <property name="password" value="password" />11            </dataSource>12        </environment>13    </environments>14    <mappers>15    <mapper class="com.github.dreamhead.moco.MockMapper"/>16    </mappers>17</configuration>

2. 请求处理适应花椒业务,url请求参数和post数据同时处理,匹配Mock数据,以及匹配优先级等特殊处理

修改moco-core工程里com.github.dreamhead.moco.internal下的MocoHandler.java方法doGetHttpResponse(),匹配规则:

  • 优先匹配用户私有的Mock数据,uri(接口uri)+ platform + uid + request参数,有则返回

  • 其次匹配非用户私有的Mock数据,uri(接口uri)+ platform + request参数,有则返回

  • 忽略请求参数匹配Mock数据,uri(接口uri)+ platform,有则返回

  • 忽略端平台匹配Mock数据,uri(接口uri),有则返回

此处之所以要做这么多优先级规则,是为了让使用Mock服务的接口能正常匹配到数据,大部分使用者在初期并没有私有数据的需求,随着场景的加深,才会设计独有的数据,所以根据使用习惯,做了分层匹配

3. https的方案更改为nginx配置处理业务证书,证书验证剥离Mock服务

java -jar mock-1.0.0-uber.jar http -p 3001 -c config.json //启动服务

本机nginx配置:

 1server { 2        listen       443 ssl http2 default_server; 3        server_name  *.*.com; //服务根域名 4        root         /usr/share/nginx/html; 5 6        ssl_certificate "/etc/nginx/ssl/tongpei.*.*.com_bundle.crt"; //证书 7        ssl_certificate_key "/etc/nginx/ssl/tongpei.*.*.com.key"; //key 8        ssl_session_cache shared:SSL:1m; 9        ssl_session_timeout  10m;10        ssl_ciphers HIGH:!aNULL:!MD5;11        ssl_prefer_server_ciphers on;1213        # Load configuration files for the default server block.14        include /etc/nginx/default.d/*.conf;1516        location / {17           proxy_pass http://127.0.0.1:3001; //跳转mock服务18        }19


业务服务器跳转处理

此处的业务服务器是app应用/前端实际使用的服务器,比如登陆服务。业务服务器的跳转处理,主要是根据用户的请求,判断是否需要跳转到Mock服务。逻辑处理是在nginx层处理的,用的luascript,提供了两个接口,一个lua/pour,用于提供给Mock后台来设置跳转信息,写到Nginx缓存里;一个lua/get,用来获取nginx现有的配置。


1、提供mock跳转配置设置/获取接口

示例

1 curl 'http://proxy.**.com/lua/pour?project=test&group=mock&ttl=' -H "Cookie: auth=lua" -d 'value={"user/1**":{"4--60":true,"4--61":true}}'23 curl 'http://proxy.**.com/lua/get?project=test&group=mock'
参数

group: 写死为mock,表示Mock配置

project: 项目名称,比如live、test等

ttl: 这个配置的过期时间,默认是3600秒

value: 配置信息,是一个json串,详见以下说明

对于配置value的说明

示例

 1{ 2    "user/1**" : { 3        "4--60" : true, 4        "4--61" : "4.4.4.4" 5    }, 6    "user/2**" : { 7        "*" : true, 8        "4--60" : "4.4.4.4" 9    },10    "*" : {11        "*" : "8.8.8.8",12        "4--67" : true,13    }14}

说明:

json数组的第一级是url,注意这个url不带前导/,第二级是uid,匹配客户端请求参数中的userid;uid对应的值为Mock地址,如果值为true,则转到默认的...(Mock服务器)

这两级都可以配置为通配符*,匹配的优先级为先匹配精确的,再匹配通配符

例如上面这个例子中,如果4--61这个用户访问user/1**接口,则会转到4.4.4.4,而4--88这个用户访问的话,会被指到8.8.8.8


2、根据配置跳转业务请求到Mock服务

 1-- 转到对应的机器 2local proxy_res = cache:get(project .. "_proxy") 3if proxy_res and proxy_res ~= "" and (ngx.req.get_headers()["x-proxy-host"] == nil or ngx.req.get_headers()["x-proxy-host"] == "") then 4    -- 增加错误处理,对于有问题的json啥的,做容错 5    local status, proxy_cnf = pcall(function(proxy_res)  6        local cjson  = require "cjson" 7        return cjson.decode(proxy_res) 8    end 9    , proxy_res)10    if status == false then11        proxy_cnf = nil12    end1314    if proxy_cnf and type(proxy_cnf) == "table" then15        if proxy_cnf[ngx.var.arg_userid] then16            ngx.req.set_header("x-proxy-host", proxy_cnf[ngx.var.arg_userid])17            ngx.exec("@proxy")18        elseif proxy_cnf[ngx.var.arg_deviceid] then19            ngx.req.set_header("x-proxy-host", proxy_cnf[ngx.var.arg_deviceid])20            ngx.exec("@proxy")21        end22    end23end



使用方法

最后的最后,一切准备就绪,使用就非常简单了

使用方式一的步骤(如图):

1. 新增要Mock接口的uri对应的返回数据

2. Mock后台新增跳转配置,如配置user/1**, uid=4--86跳转

2. 手机/前端正常操做请求,即可返回定制数据

640?wx_fmt=gif
mock
使用方式二的步骤:

1. wifi或本机hosts绑定请求接口域名到mock服务器 1.1.1.1 passport.**.com

2. 手机/前端连接绑host的wifi,返回定制数据

整个方案的过程中,我们也是一直在摸索调整,如:一开始的时候我们也并没有针对用户来做Mock数据的区分,使用时碰到开发有多人同时使用的情况,一个人改了数据,另外一个人使用时发现不对了;还有https证书的问题,花椒没有提供moco框架https服务需要的证书,为了Mock服务能同时支持客户端直接绑host的方式,采用ngnix跳转服务的方式,先处理完证书验证,再跳转到Mock服务。目前我们的Mock服务偏向于给开发人员和手工测试人员提供便捷的模拟服务,Mock在自动化测试上的应用还未被完全挖掘出来,有待进一步探讨。


界世的你当不

只做你的肩膀

640?wx_fmt=jpeg 640?wx_fmt=jpeg

 360官方技术公众号 

技术干货|一手资讯|精彩活动

空·

我知道你在看

640?wx_fmt=png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值