zoukankan      html  css  js  c++  java
  • 在 anyproxy 上做 mock 和 fuzz 测试

     

    引言

     

    写这个工具,主要有几个原因:

    1. 最近老大在尝试不同视角的测试----健壮性测试,任务下来,所以挽起袖子就开撸了

    2. app很可能因为后端api做了变更,返回了一个异常的值而出现难以预知的问题,健壮性受到碰撞,所以这种测试是有实际价值的

    3. 思寒的一篇帖子《基于 fuzz 技术验证移动端 app 的健壮性》我觉得挺好玩,这里要非常非常感谢他提供的思路,从下面的回复也可看出来大家还是比较感兴趣,而他因为遇到一些问题尚未开源,所以我挽起袖子就开撸了

    4. 社区里最近用anyproxy的挺多,我想说我们厂应该是最早开始用anyproxy的,流量测试中也使用到了这个工具。现在大家都开始定制,我表示不服,所以挽起袖子就开撸了

    5. 最近有幸被拉到了社区的技术专家群,趁着分红前多发一篇吧,哈哈

     

    0x00

     

    关于健壮性测试,模糊测试的一些描述,我希望大家可以去思寒的帖子里看,我也是从他那里出发的,我想做的东西,和他帖子里讲到的差不多,不过我又加上了另外的一些规则,总的来说,第一阶段我总结了下需求,大致如下:

    1. 只支持json结果的mock和fuzz

    2. 该走线上的还走线上,可针对某个具体api做修改

    3. 能够记录原始的request和response

    4. 在json结果中,能够指定某个key or value 进行增、删、改

    5. fuzzy化,根据原值随机返回fuzz值

    6. 轻量级 ,方便用于CI,自动化测试,而并非动辄就写个系统

    7. 跨平台

     

    0x01

    调研阶段,为了实现第一阶段的需求,并且结合公司的技术栈(python),主要是搜github 和 google,排除了下面这些:

    1. whistle ,太复杂

    2. rap,GUI界面很贴心,但是主要是为了方便前端调试,生成模板,适合后端服务还没有起来的情况

    3. mock-server,虽然python很贴合,文件保存这点做的好,但是不太方便做mock和fuzz

    4. moco,东西很好,也有点重,java栈,之前社区有同学也做过moco + anyproxy的分享

    所以,最后选用的技术栈和工具是:

    1. nodejs

    2. anyproxy

    3. jsonpath

    4. mockjs

    可以方便的模块化,打包成命令行工具,只有一个字,轻

     

    0x02

    因为这是一个依附于anyproxy的mock工具,所以anyproxy的rule_file这部分是一定要研究研究的,文档也很清楚了,我说说我踩过的坑:

    1. 截取https的请求,并不是在anyproxy的启动options里把type设置为‘https’,而是把根据rule_file里的shouldInterceptHttpsReq

    2. 做值的替换,肯定要用到replaceServerResDataAsync,这个方法的serverResData参数,是一个Buffer对象

    3. 在用jsonpath 定位后,因为我的需求里面是有api 级别的mock和global级别的mock,也有两者都有的(api会覆盖global),这在怎么区分命令行参数,以及对类似 $..name 这样的值做mock或fuzz时,增加了一定难度

    已有功能:

     

    • -s 参数是指定原始的request和response的保存路径

    • -p 指定anyproxy启动端口

    • -a 指定具体api,可以只针对这个api的返回数据做mock

    • -m 后面跟jsonpath表达式和值,比如$..name=fenfenzhong,即可把返回的结果里,所有name属性都改为fenfenzhong

    • -i 后面跟jsonpath表达式和值,可以在返回数据里置入你想要的值,对于一些由字段控制的UI特别有效

    • -d 后面跟jsonpath表达式,比如$..title,可以把返回结果里的所有title属性都删除

    有了-i(增),-d(删),-m(改),可适应的需求范围就比较广了

     

    0x03

    看看效果
    原图是:

     

    全局mock,把所有name都换成fenfenzhong,所有text都换成66666,所有title都换成lgtm

     

    $ anymocker -s save -m $..name=fenfenzhong $..text=66666 $..title=lgtm

     

    解析之后,mock规则长这样:

     

    {
      "global": {
        "mock": [
          "$..name=fenfenzhong",      "$..text=66666",      "$..title=lgtm"
        ]
      },  "api": {}}

     

    效果图是:

     

    //全局mock,把所有text都换成66666,所有title都换成lgtm,删除所有的name属性,并且植入一个属性 qa=douban
    // 本来想删除所有的title 属性的,结果。。崩溃啦

    $ anymocker -s save -m $..text=66666 $..title=lgtm -i $.qa=douban -d $..name

     

    解析之后,mock规则长这样:

     

    {
      "global": {
        "mock": [
          "$..text=66666",      "$..title=lgtm"
        ],    "inject": [
          "$.qa=douban"
        ],    "delete": [
          "$..name"
        ]
      },  "api": {}}

     

    效果图是:

    摘取某一个返回的json:

    当既指定了api,又有全局规则的时候,会先应用全局的规则,然后再应用api的规则,当两者涉及到的属性名一样时,api的会覆盖全局的。如果指定了api但是却没有命中,则只应用全局的,或者直接返回原始值

     

    //全局mock,把所有text都换成66666,所有title都换成lgtm,所有name都换成fenfenzhong,再针对具体的/api/v2/note ,把text换成sixsixsix,再增加一个属性qa=douban

    $ anymocker -a /api/v2/note/ -i $..qa=douban -d  -m $..text=sixsixsix  -m $..name=fenfenzhong $..text=66666 $..title=lgtm

     

    解析之后,mock规则长这样:

     

    {
      "global": {
        "mock": [
          "$..name=fenfenzhong",      "$..text=66666",      "$..title=lgtm"
        ]
      },  "api": {
        "/api/v2/note/": {
          "mock": [
            "$..text=sixsixsix"
          ],      "inject": [
            "$..qa=douban"
          ],      "delete": []
        }
      }}

     

    全局mock的效果图,和之前一样


    但是一个具体的日记条目里,可以看到返回的值里已经多了一个qa=douban,mock后的text值全变为了sixsixsix:

     

     

    0x03

     

    上述的几种方法可以适用于值的修改,但是有的时候需要根据原始值来进行fuzzy化处理再返回,也是可以做到的,需要把jsonpath的值指定为FUZZ,fuzzy化的规则主要有以下几个:

    1. number,string,和boolean类型的才能被fuzzy化

    2. 每种类型都有一定几率返回null

    3. 数字会随机放大缩小倍数,string会随机变为空串‘’


    //全局mock,把text,title,name都模糊处理

    $ anymocker -m $..title=FUZZ $..name=FUZZ

     

    效果图:

     

    可见第一个“小脚太太和” 的title被随机减去了一些字符,name返回了空;第二个name“萌宠”前后都加了随机字符,title返回了空,第三个“人文” 的name 和title 前都加了随机字符

     

    最后

    由上述的实验看来,工具的完成情况还不错,对于mock和fuzz都能做到,我举得栗子比较浅,但实际上它可以构造出很复杂的规则,测试数据和该走线上的可以很好的分离,而且由于是轻量级命令行的(就是个node模块),跨平台也能使用,也可以很方便的集成到CI。我自己对这种类型的测试还有一点别的思考:

    1. 这种类型的测试,主要是用随机的值,或者人为构造的极限值去挑战app,在一定程度上,能够检测app的健壮性

    2. 外部服务的失效往往会对重依赖的app产生比较大影响,拿到null值的可能性增加

    3. 这类问题的优先级可能不是那么高,怎样去构造一个现实可能出现的异常数据(如果真实不可能出现,那即使崩溃了其实也说明不了什么),对测试人员能力有较高要求


            长按二维码识别关注,您的支持是我们最大的动力。       

            公众号:测试梦工厂

            QQ一群:300897805

      

  • 相关阅读:
    clickhouse使用docker安装单机版
    nacos使用docker安装单机版
    第三周学习进度
    第二周学习进度
    二柱子四则运算定制版
    课堂测试小程序
    学习进度
    阅读计划
    自我介绍
    寻找水王
  • 原文地址:https://www.cnblogs.com/testdream/p/6220986.html
Copyright © 2011-2022 走看看