测试基础 利用 anyproxy 做 app 网络流量测试

向阳 · 2018年03月17日 · 最后由 向阳 回复于 2018年08月30日 · 5431 次阅读
本帖已被设为精华帖!

关于 app 网络流量测试,通过流量测试可以发现 app 网络资源使用情况,网络流量也是用户体验中的一项重要内容,同时通过对网络流量数据分析,也可以发现一些 app 内在的问题。

先翻了一些帖子:

Android 性能测试实践 (四) 流量
Appetizer 优化 APP 网络流量
Android App 持续集成性能测试:启动流量 (1)
[腾讯 TMQ] 常用流量测试方法及一些思考
针对流量测试,大多方法是针对 android 应用的测试方法,iOS 相关内容较少。
android 应用大概有三种测试方法:

  • 通过读取系统文件获取流量数据。获取的数据内容是整体的数据,不便做更进一步分析。
  • 通过 android 系统提供的 API 获取。可能需要 root 权限。
  • 通过其他工具收集信息 Appetizer、GT 等。
  • 通过代理抓包,wireshark 等。 iOS 可能最好的办法应该是通过工具、网络代理获取流量信息。

通过代理的方式,可以抓取到明细的数据 (请求资源地址、具体资源数据大小等),也方便做后续的具体分析,同时 android、iOS 应用均实用,不好的一点是对非 WiFi 情况需要想其他办法处理 (顺便提一下 iOS 可以通过 rvictl 做,社区也有帖子提到iOS 性能专项初探)。

入主题,本文是通过 anyproxy 做代理获取流量数据的一些测试尝试

选用 anyproxy,主要是用的多了,感觉方便,主要一点是 anyproxy 的过滤规则机制可以发挥很多作用,了解anyproxy
准备工作:准备测试机,设置代理,安装代理证书等等
anyproxy 过滤规则 rule.js ,我的过滤规则是讲请求资源地址、请求数据大小、接受数据大小记录到文件,主要内容如下:

module.exports = {

    // 获取接口的请求流量
  *beforeSendRequest(requestDetail) {
      if (requestDetail.url.indexOf("https") === 0) {
        url = requestDetail.url;
        requestLength = requestDetail.requestData.length;
        // requestLength = requestDetail.length;
        return null;
      }
  },

  // 获取接口的响应流量
  // 存储到文件
  *beforeSendResponse(requestDetail, responseDetail) {
      if (requestDetail.url.indexOf("https") === 0) {
          responseLength = responseDetail.response.body.length;
          fs.appendFile(interfaceLog, url + ',' + requestLength + ',' + responseLength + '\n', 'utf8', function(err) {
            if(err) {
              console.log(err);
            } 

          });
      return null;
    }
  },

}

标注一下:我用的 anyproxy 版本非最新版,用新版本的可以取 response header 中的 x-anyproxy-origin-content-length 字段获取返回相数据大小;还有一点这样的方式获取到数据流量大小与真实数据大小可能略有差异,我只取了一些数据与实际下载时的文件大小做了对比,后续有时间会通过使用多个工具方法等做对比。

拿淘宝 android 客户端做了一些测试

保存的 log 文件内容大致如下:

逗号做分隔,资源地址、请求数据大小、返回数据大小,单位是字节数。
然后再读取 log 文件内容,把信息存入数据库,统计数据库信息做分析。

def read_flow(log):
    # 读取anyproxy记录的流量数据计算流量
    # path = "/Users/*****"
    # filePath = path + log
    res = open(log)
    requestData = 0
    responseData = 0
    l = 0
    while 1:
        line = res.readline()
        # print "--line:", line
        if not line:
            break
        l = l + 1
        lineList = line.split(",")
        resource = lineList[0].split("?")[0]
        rex = [r'.*(?:.png|.jpg|.jpeg|.ico|.gif)', r'.*(?:.js)', r'.*(?:.css)', r'.*(?:.html)']
        reRes = 0
        type = 0
        for i in range(len(rex)):
            ls = lambda a: re.findall(rex[i], a.split("/")[-1])
            if ls(resource):
                reRes = i + 1
                break
      print "resource:", resource, reRes, "|", int(lineList[-2]), int(lineList[-1])
      # 插入数据库
        try:
            start_time = time.strftime("%Y-%m-%d %H:%M:%S")
            # insertSql = "insert into flow_2(resource, type, requestData, responseData, total_flow, create_time, tag) ****
            # db.query(insertSql)
        except:
            print u"sql插入数据库出错"
            return

取了三个场景首次启动淘宝并登录、切换淘宝底部的功能栏、查找一件商品添加到购物车并查看我的淘宝部分功能;
网络流量使用数据分别为:3.96902179718、4.89165401459、9.34268379211 单位 MB
查询数据库信息,可以清晰的看到流量占用最多的请求,重复请求次数最多的请求,图片、js、css 等等具体分类资源的请求数据
例如:
总流量消耗最多

图片流量消耗

js 流量消耗

其他资源流量消耗

这样就比较清晰了了解到具体流量消耗数据,哪些消耗最多,哪些频繁请求次数最多等等,再做针对性的分析做处理。

进一步拓展

可以将流量数据收集过程集成到自动化测试的过程中,设置好多个场景,保存不同场景的流量数据信息,做标记,多次测试取基准值,设置好阈值,在自动化测试的过程中,收集信息,超过一定的范围,则预警,也是可以发现一些有问题的功能的;同时 anyproxy 作为代理工具也可以 mock 相关数据,为自动化测试提供了方便。

现在做 app 自动化测试、专项测试的那么多,你们是怎么做的?

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 24 条回复 时间 点赞
思寒_seveniruby 将本帖设为了精华贴 03月18日 09:26

咱两名字一样,给你点个赞😂

学习了。感觉像探索性测试 ,专项测试收集数据是一部分 分析数据才是大头。没有看到楼主分析数据有些可惜

@bob_jie 我这边的 app 内嵌的 webview,对统计到的数据,分别统计 js、图片、css、api 等流量消耗占比,再具体看某一类中的重复请求次数、流量消耗排名,有一些 js、图片占用流量一次测试中多达十几兆,很明显是不合理的,后边去定位这些较高消耗项的具体问题,为什么本身流量用的多,为什么重复获取资源次数多, 针对依据什么样的标准判断流量消耗多需要处理,这个我的想法是总流量占比排名前 10,再删选重复请求资源次数排名前 10 的再去针对分析,可能这样的办法也不够成熟。

rule.js 文件在哪里修改

@chunyong 过滤规则文件是自己写的,启动 anyproxy 的时候加--rule 来使用过滤规则文件 anyproxy --intercept --rule ~/Documents/job/rule.js

@face_south 已经搞定了。多谢,想问一下,最后那个数据:请求次数是通过最后的 sql 语句整理的把?

向阳 #20 · 2018年03月27日 Author

@chunyong 是的 sql

@face_south 方便看下 mysql 建表的一些字段吗

向阳 #18 · 2018年03月27日 Author

@chunyong 文章代码里边有的 resource, type, requestData, responseData, total_flow, create_time, tag 大概就这些 自定义吧

@face_south 想问一下 为什么同一个文件请求了那么多次,而且每次返回数据大小还不一致,如同你上面图里面的.zip 和.png。 这个是由于什么原因导致的呢?

向阳 #14 · 2018年03月28日 Author

@chunyong 有几个 zip 的上传的打包数据,我猜可能是记录的埋点信息内容,这个肯定不是每次大小都一致的;png 大小不一致,本身请求的资源也不一样;这边的 app 有个情况,用到 react native,然后每个页面都是打包好的一个 js 而且名称都一样,js 占用的流量占比最大,可能和 rn 的机制有关系,具体不是很了解。

@face_south 没太明白您说的,比如一张.png 图片,连续请求了 3 次,而且每次接受数据大小还不一致。这是什么问题导致的?

向阳 #13 · 2018年03月28日 Author

@chunyong 同一张图片 连续请求三次大小不一致 没有遇到 你有链接可以直接下载一下对比数据对不对,还有一点就是请求的方式是不是不一样,get 请求,option 请求。


这个第一个图片不就是请求了 3 次吗? 三次的请求大小是一样的吗?

向阳 #11 · 2018年03月29日 Author

@chunyong
查了下我数据库的记录,是有三次请求每次的数据大小是不一致的,因为这是淘宝客户端的数据信息,我没有具体跟是什么情况,后续等我有时间我也再观察看看 (如果是记录的数据本身有问题就尴尬了)。

@face_south 不是你记录的问题,我这边测试的时候也出现了这个问题,暂时还不知道是什么原因,比较疑惑。

用这个方法测试发现好多不准确的地方,第一是:同一张图片请求次数的问题,第二:我在软件管家里面下载了一个 200MB 的游戏 app,给我输出请求和返回的流量大小都为 0; 纠结。

8楼 已删除

@chunyong 你可以这样 过滤规则文件再丰富一下,记录请求的 url 请求方式 请求数据 返回数据写到 log 文件中,这样你看看 log 内容记录的有没有问题。

麻烦问下 js 怎么写入到本地 txt 文件中

@xinxi1990
过滤规则文件可以这么写

var fs = require("fs");
var logFile = "/*/*/log.log";

module.exports = {

  *beforeSendResponse(requestDetail, responseDetail){
    // 请求数据
    const urlRequest = requestDetail.requestData;
    // 返回内容
    const urlResponse = responseDetail.response.body;
    // 可以写入时间点信息
    // 写入文件 格式自己整理
    fs.appendFileSync(logFile, " \nurl: " + requestDetail.url + "\n" + "request:" + urlRequest +"\n"+ "response:"+urlResponse, 'utf-8', function (err) {
          if (err) throw err;
          console.log('data is saved!');
          });
    }
}

@face_south 您好,我这边用了下,不生成 log 文件

向阳 #26 · 2018年08月30日 Author

@plateau520 检查代理设置好了吗 log 地址写的有没有问题,看看输出的内容里边有没有报错信息

simple 专栏文章:[精华帖] 社区历年精华帖分类归总 中提及了此贴 12月13日 14:44
simple [精彩盘点] TesterHome 社区 2018 年 度精华帖 中提及了此贴 01月07日 12:08
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册