Appium + mitmProxy 实现APP接口稳定性测试!

1576 篇文章 63 订阅
1479 篇文章 54 订阅

1.背景介绍

为了保障 App 的稳定性,我们现在有 XMoney 智能遍历测试(崩溃、界面错乱、加载异常等)、UI 自动化(崩溃和业务逻辑验证)、Top1000 小程序遍历(崩溃和业务逻辑报错)、接口稳定性建设(崩溃和业务逻辑验证)。 今天要给大家介绍的是接口稳定性建设,就是在后端返回数据如果不可靠的情况下,App 是否依然可以稳定运行。

2.实现思路

方案一

Mock有专门的Mock平台, 崩溃有专门的崩溃监控平台, 我们只需要把Mock数据下发到手机,如果有崩溃,会被崩溃平台收集到,崩溃会由值班同学分发给研发。

1. 将接口代理到Mock平台,Mock平台根据response 生成批量的Mock数据

2. 通过Appium调用App到制定页面, 触发对应请求,请求到了Mock平台后,Mock平台随机下发Mock数据

3. 重复打开指定页面, 直到遍历完Mock数据

4. 崩溃平台进行崩溃分发(人工)

  优点:

  短时间内可以覆盖大量的mock数据。

  缺点:

  mock数据不可控。

现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:691998057【暗号:csdn999】

方案二

  方案一有太多的随机性,为了让下发的数据和下发数据后的结果能够对应, 我们为了控制下发的数据, 我们在方案一的基础上自建Mock server, 通过Appium脚本和Mock server的交互,控制下发数据。

  经调研,Mock server 比较大众的方案就是采用[mitmproxy](https://github.com/mitmproxy/mitmproxy), [mitmproxy](https://github.com/mitmproxy/mitmproxy)可实现 python 脚本的注入, 通过 python 脚本可以拦截请求的 request 和 response 数据,然后篡改数据后返回。因为 mitmproxy 是一个shell工具, 无法直接和python脚本交互, 所以python脚本和mitproxy的交互方式采用的是.ini的形式,互相读取 .ini 文件中的内容来实现数据交互。

  优点:

  mock数据可控制,可以校验预期结果。

  缺点:

  需要准备mock数据, mock数据要经常维护。

  2种方案我们都有应用,方案一较为简单,在集成测试阶段执行,我们不再展开介绍。 方案二稍微麻烦一些,回归测试阶段执行。以下将详细介绍下方案二如何实现。

  3.代码设计

  方案流程

  代码示例

  测试Case

  通过Mock更新数据,测试小程序升级的逻辑 (因涉及代码较多,大家可通过完整系统查看)

  测试小程序的同步升级和异步升级逻辑, 修改测试配置后,mitmproxy会监控对应的接口请求, 发现存在要修改数据的请求,则进行response修改后返回给手机端。 手机端验证是否升级成功。

  步骤:

  1. 修改测试配置(通过ini文件和mitmproxy实现联动, mitmproxy会在每次触发接口请求时检测当前的测试配置文件)

  2. 打开手机app

  3. 打开某个小程序

  4. 验证是否升级成功 (示例为把官方小程序Demo升级成为携程小程序)

  @File   : test_update.py

  @Author : YangTongGang

  @Desc   : 小程序升级(同步更新、异步更新)

  class TestUpdate(BaseTestCases):

  检测小程序同步更新、异步更新

  已适配(iOS & Android)

  def setUp(self) -> None:

  # super(TestUpdate, self).setUp()

  self.business.del_sf_app('智能小程序')

  if self.is_android:

  self.business.del_sf_mine_app('智能小程序')

  def __update_action(self, is_sync=True):

      # 把CTS升级成携程, 并修改max age = 0

      # 控制mitmproxy进行不同的测试

      if is_sync:

          test_type = TestType.TestMaxAgeZero

      else:

          test_type = TestType.TestSaveResponse

      self.changeTestType(test_type)

      protocol = CaseManager.official_demo_case().protocol

      self.business.open_swan(protocol)

      if is_sync:

          test_type = TestType.TestSyncUpdate

      else:

          test_type = TestType.TestAsyncUpdate

      self.changeTestType(test_type)

  def test_max_age_force_update(self):

      """测试小程序同步更新"""

      self.__update_action()

      self.business.open_app()

      protocol = CaseManager.official_demo_case().protocol

      if self.business.open_swan(protocol):

          self.assert_validate('汽车票')

  Mitmproxy 启动

  通过shell脚本启动mitmproxy并加载 http_handle.py文件,加载的python文件通过重写response或者request来达到监控每次请求的request和response的能力。

  每次收到测试任务时,测试任务都会有相应的配置, 如果发现需要启动代理服务,则会自动调用如下脚本,启动代理, 然后手动配置测试机代理到服务地址,或者把任务打到固定的测试机上。

  #!/usr/bin/env bash

  : '

  @File   : start_ui_mock.sh

  @Author : YangTongGang

  @Desc   : 启动UI Mock服务

  '

  script_file=/CaseTester/HTTPRouter/http_router.py

  path=$0

  current_path=${path%/*}

  current_path=${current_path%/*}

  # 启动mock 数据服务

  file=/SHELL/start_mock.sh

  file_path=${current_path}${file}

  chmod +x "${file_path}"

  sh "${file_path}" ${script_file}

  #!/usr/bin/env bash

  : '

  @File   : start_mock.sh

  @Author : YangTongGang

  @Desc   : 启动接口Mock服务

  '

  path=$0

  file_path=$1

  current_path=${path%/*}

  current_path=${current_path%/*}

  file_path=${current_path}'/..'${file_path}

  echo "${file_path}"

  local_ip=$(ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"|head -n 1)

  echo '=========== 代理服务地址 ============'

  echo 'Script:' "${file_path##*/}"

  echo ''

  echo "${local_ip}":8088

  echo ''

  echo '==================================='

  # mitmdump -s "${file_path}" -p 8088  --flow-detail 0

  status=$(mitmdump -s ${file_path} -p 8088  --flow-detail 0)

  if [$? == 0]

  then

      exit 0

  fi

  监控response

  注册对应的接口处理模块,遇到对应的接口时执行对应的测试。

  """

  @File   : http_router.py

  @Author : YangTongGang

  @Desc   : 请求中转站

  """

  # 注册handle

  HANDLES = [

      # Core更新请求

      UpdateCoreHandle,

      # APS拉包请求

      PkgAPSHandle,

      # PMS拉包请求

      PkgPMSHandle,

      # Update接口

      UpdateHandle,

      # 我的页面, 下拉二楼的静默更新个数

      GetPkgListHandle

  ]

  def response(flow):

      """接口response"""

      url = flow.request.url

      path = urlparse.urlsplit(url)['path']

      proxy_mock_urls = []

      for handle in HANDLES:

          proxy_mock_urls.append(handle.identifier)

      test_type = get_proxy_test_type()

      if test_type == TestType.TestNone:

          return

      if path not in proxy_mock_urls:

          return

      response_dic = json.loads(flow.response.content)

      for handle in HANDLES:

          if handle.identifier in path:

              handler = handle(response_dic, test_type)

              response_dic = handler.package_dic

              flow.response.content = bytes(json.dumps(response_dic), encoding='utf8')

              return

  4.机房设计简介

  为了方便理解整个业务设计,顺便把我们的机房设计也给大家简单介绍一下。任务执行一般都是通过流水线派发到指定机房的随机空闲手机,测试完成后直接返回测试报告,测试执行人无需关心中间过程,也无需维护各种脚本。脚本都在机房维护, 避免在本地Appium部署困难, 脚本更新不及时等问题。

  5.结语

  因为实际使用过程中依然需要大量人工介入,收益较小,所以执行频率不高,且该方案时间略微久远,所以在此只给大家抛砖引玉,开拓下思路之用,后续如有需要可以作为一种备选方案。

下面是配套资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!

最后: 可以在公众号:程序员小濠 ! 免费领取一份216页软件测试工程师面试宝典文档资料。以及相对应的视频学习教程免费分享!,其中包括了有基础知识、Linux必备、Shell、互联网程序原理、Mysql数据库、抓包工具专题、接口测试工具、测试进阶-Python编程、Web自动化测试、APP自动化测试、接口自动化测试、测试高级持续集成、测试架构开发测试框架、性能测试、安全测试等。

如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!

  • 17
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值