开源测试工具 接口测试工具之 httpapi (类似 gor,抓流量,回放,diff,fuzz)

zhangzhao_lenovo · October 31, 2016 · Last by minizuo replied at April 26, 2018 · 5038 hits
本帖已被设为精华帖!

接口测试一工具,好不好用,用了就知道

优势

  1. 无需写测试用例!
  2. 所做即所得,真实记录流量,多次测试复用!
  3. 结构化diff,简化结果校验!
  4. 中间化插件,解决动态参数!
  5. 自动fuzz测试各种容错!
  6. 无缝对接持续集成

原理

  • 如何实现了记录和回放?

二次开发fiddlerscript实现自己的OnBeforeResponse,开启fiddler实时记录抓取指定数据包的请求和回应

static function OnBeforeResponse(oSession: Session) {
if (isautocap && oSession.HostnameIs(filterUrl)) {
if (oSession.responseCode != 200 || oSession.GetResponseBodyAsString().IndexOf("\"errno\":0") != 1){
record(oSession,filePath + "refuse.gor",8);

static function record(oSession:Session,fpath:String,op:int){
oSession.utilDecodeResponse();
var sBuilder = new StringBuilder();
sBuilder.Append("\n"+"Request id: 1 " + getmd5(oSession.url) +" "+ oSession.Timers.ClientBeginRequest.Ticks+" "+getmd5(oSession.PathAndQuery.split('?')[0])+"\n");
sBuilder.Append("Request protocol: " + oSession.isHTTPS+"\n");
sBuilder.Append("Request url: " + oSession.url+"\n");
sBuilder.Append("Request api: " + oSession.PathAndQuery.split('?')[0]+"\n");

从记录的文件中读取数据包原始的请求结构,经中间件处理后,调requests库发包

def send(url,method,payload,headers,**attrs):
if method == 'POST':
r = requests.post(url, data=payload, headers=headers,**attrs)
if method == 'GET':
r = requests.get(url, data=payload, headers=headers,**attrs)
return (r.status_code,r.json(),r.headers)
  • 如何解决动态token?

运行时获取包的response再经中间件middleware修正后续包的request

def fifoprocess(queue,n):
while True:
try:
n-=1
j=n
str = queue.popleft()
(code,body, header)=process(str)
while(j>0):
queue.append(middleware.rule(str,body,header,queue.popleft()))
j-=1
fifoprocess(queue,n)

利用一个双向队列弹栈发包,修正后再入栈。该方法效率有待改善

middleware具体算法需根据项目情况自己实现逻辑

def rule(str,body,header,pstr):
"""
url=str.split('Request ')[3].split("
?")[0].split(" ")[1].replace("\n","")
if url=='www.3663.com/api/msg/send':
body=eval(body)
token=urllib.parse.quote(body["
data"])
pstr,_=re.subn("
content=(.*)&","content="+token+"&",pstr)
"""

return pstr
  • 如何diff?

首次运行测试时会根据包返回与记录文件中原包返回做结构化对比,生成差异white.txt,认为是一次diff baseline

white.txt
www.xxxx.com/api/index/banner header.Transfer-Encoding
www.xxxx.com/api/room/get header.Content-Length
www.xxxx.com/api/room/init body.data.room_info.stream_status
www.xxxx.com/api/room/init body.data.anchor_info.uid
www.xxxx.com/api/room/init body.data.chat_info.url
www.xxxx.com/api/room/get header.Date

后续测试会根据本次包返回与上次包返回做对比,差异屏蔽掉白名单之后的diff作为测试结果供人工校验

也可手动删除white.txt,连续2次测试来生成baseline

实际测试人员只需确认记录的原包,生成的white.txt,以及后需的diff。无需用例无需手工重复执行,简化了其测试成本

  • 关于fuzz

同样利用记录文件,读取原包request结构自动遍历一些基本的fuzz测试 ,如缺参数,空值,无值,字符串裁减、扩展、异常值,超长,特殊值等。

也可自行添加fuzzcase 如xss等


适用场景

  1. fuzz测试--新接口
  2. 回放测试--接口线上监控,回归测试,环境切换

开源地址

https://github.com/zhangzhao4444/httpapi

如有bug和好想法可及时联系我

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 32 条回复 时间 点赞

好东西,支持一个

mac 好像不行吧

#2楼 @pacerron 恩,我在win7-64上实现的,没有mac可用。其实也可以借助mac上的抓包工具 比如burpsuite,方法是类似的,猜测也有类似OnBeforeResponse接口重写下,把包记录record文件 后面都一样了

嗯,我有个问题,就是回放的时候,比如有些key 只能生效一次,回放再调用一次就不能用了。
另外,你这个和论坛里也有个人做的复制接口好像差不多

#4楼 @pacerron 有些key 只能生效一次,回放再调用一次就不能用了。 说的是动态参数比如token吧,这个利用中间件可以动态解决的

谢谢分享,最近搞好想研究下这方面的知识

思寒_seveniruby 将本帖设为了精华贴 31 Oct 20:56

加精理由: 开源 设计思路优秀

#5楼 @zhangzhao_lenovo 没明白 能细说下吗

很使用哦 点赞

#11楼 @heyniu 是的,你的

#12楼 @pacerron 懒了,很久没更新这套了,服务器一直没空帮我自定义测试报告,停在那里了

#13楼 @heyniu 呵呵,空下来再搞搞

#9楼 @pacerron 这个工具灵感来源于那个开源的gor,一直跟了一段时间。

解决token等动态参数需要自编写middleware.py的逻辑,大致流程:
获取packet a的request-->send a-->得到真实的a response-->经过middleware中间件-->根据逻辑修正 other packet-->send b

def rule(str,body,header,pstr): #str a,a的response body,a的response header,pstr b的原始包
url=str.split('Request ')[3].split("?")[0].split(" ")[1].replace("\n","")
if url=='xxx/api/msg/send':

body=eval(body)
token=urllib.parse.quote(body["token"])
pstr,_=re.subn("content=(.*)&","content="+token+"&",pstr)
return pstr
判断如果a是指定url ,获取其动态返回的token,按正则替换到b中

仅是个例子,实际通常需要一些加密算法,或者从cookies中提取

我也用fiddler脚本实现类似用例录制的功能,查了好久才发现时.net脚本😅

想请教一下fiddlerjsconf.ini里的

"filterUrl":"www.3663.com",

用来做什么?

#17楼 @orangec 劫持的指定域名,相当于录制的一个过滤条件,根据自身项目情况修改

zhangzhao_lenovo [Topic was deleted] 中提及了此贴 16 Nov 15:44

mark后续需要时,再来讨取

python碰到java写的那些自定义的加密方法就比较难处理了吧~其中最常见的莫过于签名了

22Floor has been deleted
23Floor has been deleted
24Floor has been deleted

#21楼 @kasi 哦。感觉还好,我接触的几个项目 加密这块python都可以搞定,其实实在不行python也能直接调jar

回复出bug了。。点1次出了4条

#26楼 @zhangzhao_lenovo 重复的帮你删了:)

@zhangzhao_lenovo python是可以调用jar包,但是一次工程中,只能调用一次,而不腻频繁调用,这个是jpype的一个坑,所以不合适,加密是自定义的,除非用python自己重写加密算法,不然只能走其他方式处理的

#28楼 @kasi 我们的接口mock也需要做一些数据处理,用的是java,比如你提到的加密,因为是安卓项目,所以直接用java比较稳妥一些。

@simple 是的,python处理这一块还是比较吃力,虽然有方法解决,但是碰到例如hessian类协议的处理便捷性不如java,我这边的接口语言后续重构的时候会切换为java

感觉动态结果验证是最重要也最不好做的,目前还处于只验证状态码、格式、和相对固定的字段的阶段

有个疑问,如果只是给的接口文档怎么测试?

嗯可以把它想象成一个录像回放机 利用对比的思路进行测试。有无接口文档影响不大,录制时的操作决定了要测哪些内容

你好 我正在研究这个 请问 怎么可以联系你 私聊啊 大神:😀

我在抓取一个APP的新闻动态评论,然后通过filter 过滤 选择关键词 comment,然后只剩下 我需要的会话。我想通过fiddlerscript 编程能够自动保存我所筛选的信息到本地数据库或者文档之中。 还请指点🎁

瀚海星星 回复

sorry 刚看到 qq 77227005

最关键的问题:diff背后的环境是如何搞的?如果是线上流量除了token替换还做了什么处理保证线下可以回放?如果是线下测试环境流量,如何保证能二次回放?所以想知道背后数据和依赖环境都怎么设计解决的呢,理想的diff肯定是既diff回包内容也diff了落地数据。

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up