1 背景

1.1 作者背景

作者在过去一年多内,在某大型游戏公司负责游戏 SDK 业务的质量保障工作,在客户端自动化测试方面有一定的探索和实践。

1.2 项目背景

1.2.1 为什么要做客户端自动化测试

相信这个问题的答案,大家心里都有答案。有人说是:发现 bug,验证功能;有人说是:降低回归测试成本;有人说是:提高测试能力;不一而足。

对于 SDK 业务而言,无论是登录还是支付,稳定性要求都非常高,不允许出现失误。软件的变动(包括客户端和服务端)是否会影响功能,如果能在客户端层面进行自动化的确认,不论对质量,还是效率,都有很重要的意义。

除了测试能力对开发服务开放以外,我们还需要对运维服务。

自 2020 年以来,世界经济都在下行,各家公司整体都在降本增效,以应对经济下行的压力。与此同时,微服务和多中间件架构已经成为了各家公司的标配,这些中间件和服务器平时实际使用率并不高,存在优化的空间。公司倾向于缩减硬件成本,运维也有 KPI 要求。对于测试人员的影响就是:服务端和中间件的硬件变动需要一定的回归测试来验证。在我们团队中,这种情况不是一次两次,而是在整个降本周期内一直存在。

1.2.2 为什么能做客户端自动化测试

任何一个决策,都应该考虑可行性,客户端自动化测试也不例外。

根据测试金字塔理论,客户端自动化测试因为以下几个问题,导致其性价比不如集成测试。

  • 1.UI 层变化太大,测试用例需要频繁改动,维护成本较高;

  • 2.集成度最高,难以准确定位故障;

  • 3.用真实设备来实施测试,实施成本最高;

  • 4.客户端的进程过多,导致其测试以外的干扰因素过多,因此稳定性较差。

因为业务独特的情况,这几个问题均可得到一定程度的削弱,可行性反而较高:

  • 1.游戏 SDK 有对应的客户端 DEMO,UI 层变化很小,即使变化往往也是 UI 树增加子节点,不影响定位原来的元素。

  • 2.由于游戏 SDK 的核心功能只有登录和支付,业务链路单一且功能相对平行,不会有太多的业务耦合,故障定位比较简单。举个栗子:支付宝支付挂了,要么是支付宝支付链路上的问题,不会影响微信支付的用例,除非是支付底层逻辑问题。退一步讲,上述情况发生了,定位也是比较容易的。

  • 3.无论是 Android Studio 还是 Xcode,其实都是支持模拟器的,我们可以借助模拟器来做测试,可以极大地降低硬件成本。可行原因参考本文:2.关于使用模拟器做自动化测试的调研。

  • 4.由于创建的模拟器没有安装太多应用,应用之间的干扰比较小。且模拟器在电脑中,网络环境比较好。

1.3 常见误区

1.3.1 期望客户端自动化测试能够测试出兼容性问题

客户端自动化测试不等于兼容性测试,不需要测试各种机型,各种屏幕的设备。那是兼容性测试的工作,自动化测试的核心还是降低测试执行成本,确认质量符合要求。

1.3.2 期望测试用例稳定性到 100%,不能存在误报

任何测试都会存在干扰因素,不可能 100% 稳定:硬件设备断电,网络不稳定,进程卡死,服务端测试环境故障,服务端和客户端配置错误,测试框架出 Bug,甚至真机设备上的系统弹窗都会导致测试用例失败。误报确实是衡量客户端测试有效性的重要因素,但不应该成为衡量的唯一因素。

我们应该秉持的态度是:一方面在误报出现时,尽快由测试人员介入确认该误报;另一方面不断完善测试框架,尽可能消除这些干扰因素。

1.4 技术栈选型

团队成员对 Python 和 Airtest 比较熟悉,并且之前有成熟的测试项目。Pytest 有丰富的测试插件,开发效率较高。此外可以自己编写钩子,本测试框架在配置测试环境、生成测试报告、发送测试邮件等环节多次用到了钩子。为了快速出成果,故选用了 Pytest + Airtest。

此外,为了紧跟前沿测试,使用了行为驱动开发的思想。测试驱动开发的思想,想必大家都有所耳闻。行为驱动开发,其实是前者的一种升级。应用在测试领域,就是行为驱动测试,它定义了每个测试步骤,并赋予了这些测试步骤一定的代码,使其能够实现这个测试步骤。如果只做到这些,那还不够诱人,行为驱动测试允许测试步骤的复用。具体示例请参考本文:4.1 测试脚本

Behavior-driven development is an extension of test-driven development, a development process that makes use of a simple DSL. These DSLs convert structured natural language statements into executable tests. The result is a closer relationship to acceptance criteria for a given function and the tests used to validate that functionality. As such it is a natural extension of TDD testing in general.

From Wikipedia: Behavior-driven development

2 关于使用模拟器做自动化测试的调研

正如前文所说,可以创建客户端模拟器用于客户端自动化测试,可以降低硬件成本。对于这一设想的可行性,作者花了较多时间做了深度调研,打通了模拟器客户端自动化测试的各个环节。

2.1 创建模拟器

对于安卓设备有:

# 切换到Android sdk的根目录cd /Users/<username>/Library/Android/sdk# 创建模拟器./tools/bin/avdmanager create avd -n <emulator_name> -k "system-images;android-22;google_apis;arm64-v8a"# 重命名模拟器./tools/bin/avdmanager move avd -n <emulator_name> <new_emulator_name># 删除模拟器./tools/bin/avdmanager delete avd -n <emulator_name># 启动模拟器./emulator/emulator -avd Pixel_5_API_22 & bg# 关闭模拟器kill `ps aux | grep Android/sdk/emulator/qemu | xargs | awk -F ' ' 'END{print $2}'`

对于iOS设备:

# 创建模拟器,机型iPhone-13-Pro-Max,系统版本iOS-15-2xcrun simctl create my_iphone_pro_max com.apple.CoreSimulator.SimDeviceType.iPhone-13-Pro-Max com.apple.CoreSimulator.SimRuntime.iOS-15-2# 删除模拟器xcrun simctl delete my_iphone_pro_max# 启动模拟器xcrun simctl boot my_iphone_pro_max# 关闭模拟器xcrun simctl shutdown my_iphone_pro_max# 检查设备的运行状态xcrun simctl bootstatus my_iphone_pro_max# 找到正在启动的模拟器设备xcrun simctl list | grep Booted# 给设备起一个别名xcrun simctl 7CD4F140-0BDC-4AE9-8FA0-960D33055044 rename my_iphone_pro_max

simctl提供了更为丰富的 api,可以实现更多的功能。

使用 Python 代码封装上述的命令,即是整个框架的底层工具包。

2.2 连接模拟器

连接模拟器的教程,网易的 Airtest 文档朱玉在前,我就不做赘述,请参考:

如何在 iOS 手机上进行自动化测试

如何在 Android 手机上进行自动化测试(上)

如何在 Android 手机上进行自动化测试(下)

# Tiffany.pyfrom poco.drivers.ios import iosPocofrom poco.drivers.android.uiautomation import AndroidUiautomationPocofrom airtest.core.api import auto_setup, connect_devicefrom cases.utils import config_parserclass Tiffany(object):"""底层工具箱"""def __init__(self, app_name: str) -> None:self.app_name = app_namedef make_android_poco(self) -> None:auto_setup(__file__)connect_device(uri=config_parser.get("DEVICE", "EMULATOR"))self.poco = AndroidUiautomationPoco(pre_action_wait_for_appearance=3,action_interval=0.5,poll_interval=0.4)def make_ios_poco(self) -> None:auto_setup(__file__, devices=[config_parser.get("DEVICE", "IPHONE_URI"), ]connect_device(config_parser.get("DEVICE", "IPHONE_URI"))self.poco = iosPoco(pre_action_wait_for_appearance=4,action_interval=0.1,poll_interval=0.2)

2.3 操作模拟器

对于 Android 设备,有祖传的 adb 命令来操作:

# 列出连接的设备./platform-tools/adb devices# 列出app./platform-tools/adb -s Pixel_5_API_22 shell pm list packages# 安装测试应用./platform-tools/adb -s Pixel_5_API_22 install <path_to_apk>.apk# 启动pocoservice./platform-tools/adb shell am start -n com.netease.open.pocoservice/com.netease.open.pocoservice.TestActivity# 启动测试应用./platform-tools/adb -s Pixel_5_API_22 shell am start com.example.sdk.demo.activity.SplashActivity# 卸载测试应用./platform-tools/adb -s Pixel_5_API_22 uninstall com.example.sdk.demo

对于 iOS 设备,有xcrun simctl命令来操作:

# 安装应用到指定的设备xcrun simctl install my_iphone_pro_max resources/packages/IOSDemoMainland.app# 卸载指定应用,根据bundle_idxcrun simctl uninstall my_iphone_pro_max com.netease.boltrend.sdk.demo# 列出已安装的应用xcrun simctl listapps my_iphone_pro_max# 查看app信息xcrun simctl appinfo my_iphone_pro_max com.apple.mobilesafari# 启动appxcrun simctl launch my_iphone_pro_max com.apple.mobilesafari# 关闭appxcrun simctl terminate my_iphone_pro_max com.apple.mobilesafari# 打开urlxcrun simctl openurl my_iphone_pro_max https://cn.bing.com/# Sure, you can use the global macOS shortcut to capture a screenshot of a simulator (⇧⌘4), but if you intend to use those for your App Store listing, you’re much better off using the io subcommand:$ xcrun simctl io booted screenshot app-screenshot.png# You can also use this subcommand to capture a video as you interact with your app from the simulator (or don’t, in the case of automated UI tests):$ xcrun simctl io booted recordVideo app-preview.mp4

此外,tidevice 也是好用的工具。详细用法请参考:阿里Python自动化工具 tidevice 使用指南

3 总体设计

总体设计架构如下:

4 详细设计

4.1 测试脚本

下面重点讲讲测试脚本编写:

4.1.1 定义测试步骤

针对一个邮箱登录的测试场景,可以用 gherkin 语言定义下面的测试步骤:

# mail_login_test.featureFeature: mail_login_testtestcases about mail login  Scenario: mail login with correct password    Given start app and initialize settings    And open the main board    When I admit agreements on login board    And I go to the mail login board    And I input correct password and login    Then assert login success

4.1.2 编写测试代码

每个测试步骤,都有对应的

# mail_login_test.pyfrom pytest_bdd import given, then, when@given('start app and initialize settings')def start_app_and_initialize_settings() -> None:"""启动app,初始化设置"""pass@given('open the main board')def open_the_main_board() -> None:"""打开登陆面板"""pass@when("I admit agreements on login board")def admit_agreements_on_login_board() -> None:"""同意用户协议"""pass@when("I go to the mail login board")def to_mail_login_board() -> None:"""到邮箱账号登录面板"""pass@when("I input correct password and login")def input_correct_password_and_mail_login() -> None:"""邮箱登录,输入正确的密码"""pass@then('assert login success')def login_success() -> None:"""断言登陆成功"""pass@scenario('mail_login.feature', 'mail login with correct password')def test_mail_login_with_correct_password() -> None:"""邮箱登录测试用例"""pass

4.1.3 代码复用示例

可复用的步骤可以放到conftest.py中,比如:start app and initialize settings,open the main board,I admit agreements on login board,代码示例如下:

# conftest.pydef initialize_environment(apk_name: str) -> None:"""初始化测试环境:param apk_name:  apk包名:return: None"""pass

对于支付宝支付的测试用例,需要登陆操作,显然可以复用邮箱登录的步骤。

# alipay_test.featureFeature: alipay_testtestcases about alipay  Scenario: 支付宝支付,编辑商品信息,拉起支付窗口,验证支付是否调起    Given start app and initialize settings    And open the main board    When I admit agreements on login board    And I go to the mail login board    And I input correct password and login    Then assert login success    When I prepare the order information with CNY    And I place an order of alipay    Then alipay cashier desk will show up

由于复用了邮箱登录的步骤,上述拉起支付宝窗口的用例,只需要专注于下订单拉起支付的逻辑。

# alipay_test.py@when("I prepare the order information with CNY")def prepare_order_information() -> None:"""准备订单信息"""pass@when("I place an order of alipay")def place_an_order() -> None:"""下订单"""pass@then("alipay cashier desk will show up")def assert_alipay_cashier_desk_shows_up() -> None:"""展示收银台"""pass

4.1.4 测试数据统计

Pytest 有钩子支持二次开发,在pytest_runtest_makereport钩子内。

def pytest_runtest_makereport(item, call) -> None:"""统计测试数据"""pass

4.1.5 回传统计数据

在钩子pytest_runtest_makereport(item, call)编写数据持久化逻辑。若使用 jenkins,则直接往数据库写数据。若使用自研服务,则调用服务端接口,回传测试数据。

def pytest_sessionfinish(session, exitstatus) -> None:"""调用调度服务的接口,上传测试数据"""pass

4.1.6 发送测试报告

jinja2库支持编写邮件网页,email库支持发送邮件。

4.2 调度服务

4.2.1 调度服务设计

调度服务和 Web 前端,可以用 jenkins 代替。相应地,开发成本降低,可以快速出效果,但是展示效果要打折扣,数据处理逻辑也更依赖 pytest 钩子的二次开发。

服务端框架推荐:Flask,可以快速出成果。以创建任务为例:

@app.route("/testtask/create", methods=["POST"])def create_test_task() -> str:pass

4.2.2 远程执行命令

本地机器生成私钥和公钥

$ ssh-keygen -t rsa

把公钥存放到远程机器上

$ scp ~/.ssh/id_rsa.pub zhancc@192.168.94.111:~/.ssh/id_rsa.pub

把公钥添加到远程机器的authorized_keys

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

远程执行命令

ssh zhancc@192.168.94.111 "/Users/<username>/Library/Android/sdk/tools/bin/avdmanager create avd -n <emulator_name> -k system-images;android-22;google_apis;arm64-v8a"

Python 调用命令

import subprocessdef execute_bash(command: str, timeout: int = 10) -> tuple:"""执行shell脚本:param command: 脚本:param timeout: 超时时间,默认为10秒:return: stdout, stderr 标准输出和错误"""sp = subprocess.Popen(command, shell=True)return sp.communicate(timeout=timeout)

4.2.3 支持异步任务

各种命令调用,用同步任务,性能将会很差,且模块耦合较高。使用 celery 异步任务将会提高性能,以调用远程命令为例:

from utils import Machinefrom celery import Celerycelery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])celery.conf.update(app.config)@celery.taskdef execute_remote_command(machine: Machine, command):"""执行远程命令"""pass

4.2.4 支持定时任务

为了支持定时触发测试任务,推荐使用APScheduler

from apscheduler.schedulers.background import BlockingSchedulerscheduler = BlockingScheduler()scheduler.add_executor('processpool')def trigger_test() -> None:"""触发测试任务"""passscheduler.add_job(ui_test, args=("iOS_SDK_Client_Test", "mainland", "qa"),trigger='cron', minute="07", hour="5", timezone=ZoneInfo("Asia/Shanghai"))scheduler.add_listener(task_listener, EVENT_JOB_ERROR)print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))try:scheduler.start()except (KeyboardInterrupt, SystemExit):pass

4.2.5 Web 后台

利用 Vue.js 快速实现 Web 后台,在此不过多介绍。

5 结语

5.1 应用拓展

  • 系统版本的兼容性测试:由于模拟器的系统版本众多,理论上可以做 Android 和 iOS 系统版本的兼容性测试。

  • 云模拟器服务:商业案例有:https://appetize.io/demo

5.2 作者的话

今年9月份找到公司法务,想把这个发成客户端自动化测试专利,法务说你这个方案与一些已有专利相似度较高。既然发不了,不如就分享给大家,共勉!

参考文档

1.The Testing Pyramid: Simplified for One and All

2.Just Say No to More End-to-End Tests

3.Android Studio - avdmanager

4.simctl Written by Mattt November 26th, 2018

5.Best iOS simulators for Windows and Mac for 2022

6.阿里 Python 自动化工具 tidevice 使用指南

7.如何在 Android 手机上进行自动化测试(上)

8.如何在 Android 手机上进行自动化测试(下)

9.如何在 iOS 手机上进行自动化测试

10.BDD (Behavior Driven Development) Framework: A Complete Tutorial

11.Behavior-Driven Development(BDD) Testing

12.ssh 密钥登录及远程执行命令

13.Pytest Documentation

14.Flask Documentation

15.APScheduler Documentation

16.Celery - 分布式任务队列


资源分享【这份资料必须领取~】

下方这份完整的软件测试视频学习教程已经上传CSDN官方认证的二维码,朋友们如果需要可以自行免费领取 【保证100%免费】

模拟器客户端自动化测试实践相关推荐

  1. 基于Sikuli GUI图像识别框架的PC客户端自动化测试实践

    一.GUI图像识别框架元祖:Sikuli Sikuli 创始于 2009 年,是麻省理工学院用户界面设计小组的一个开源研究项目.2012 年由 RaiMan 接管开发和 支持并将其命名为 Sikuli ...

  2. 客户端自动化测试研究

    测试作为质量保证极其重要的一环,在移动App开发流程中起到非常关键的作用.从开发工程师到测试工程师,人人都应具备良好的测试意识,将隐患和风险在上线之前找出并解决,可以有效的减少线上事故. 美团和大众点 ...

  3. 美团团队---客户端自动化测试研究

    测试作为质量保证极其重要的一环,在移动App开发流程中起到非常关键的作用.从开发工程师到测试工程师,人人都应具备良好的测试意识,将隐患和风险在上线之前找出并解决,可以有效的减少线上事故. 美团和大众点 ...

  4. 接口自动化测试实践指导(中):接口测试场景有哪些

    在第一篇文章 接口自动化测试实践指导(上):接口自动化需要做哪些准备工作中详细给小伙伴们讲解了一下接口自动化需要做哪些准备工作,准备工作中最后一步接口测试用例设计是非常重要的一个环节,用例设计的好不好 ...

  5. 收钱吧的 Python 高效自动化测试实践

    1. 背景 收钱吧业务服务千万级商家,业务庞大,产品背后有复杂的应用支撑.我们采用了微服务架构,有成百上千个不同类型的后端服务,使用了包括Node.js.Java.Go.Python等后端语言,还有M ...

  6. 安卓模拟器获取服务器信息出错,安卓模拟器客户端与服务器不同步

    安卓模拟器客户端与服务器不同步 内容精选 换一换 目前从本地或虚拟机通过DRS备份迁移功能直接迁移到本云RDS for SQL Server实例上,在迁移完成后还需要针对Login账号,DBLink, ...

  7. appium+java(五)微信小程序自动化测试实践

    前言: 上一篇<appium+java(四)微信公众号自动化测试实践>中,尝试使用appium实现微信公众号自动化测试,接着尝试小程序自动化,以学院小程序为例 准备工作 1.java-cl ...

  8. Lego-美团点评接口自动化测试实践

    Lego-美团点评接口自动化测试实践 2018-02-07 转自:Lego-美团点评接口自动化测试实践 目录 一.概述   1.1 接口自动化概述   1.2 提高ROI     针对"减少 ...

  9. 【Electron】酷家乐客户端开发实践分享 — 下载管理器

    作者:钟离,酷家乐PC客户端负责人 原文地址:webfe.kujiale.com/electron-ku- 酷家乐客户端:下载地址 www.kujiale.com/activity/13- 文章背景: ...

最新文章

  1. 模拟请求分页管理中地址转换和缺页中断处理_Linux内存管理:缺页异常(一)
  2. 搭建QT和VS2010集成开发环境
  3. MySQL教程(一)—— 数据库设计
  4. TensorFlow 2.0 - TFRecord存储数据集、@tf.function图执行模式、tf.TensorArray、tf.config分配GPU
  5. 阿里专家杜万:Java响应式编程,一文全面解读
  6. 【Docker】容器镜像有哪些特性
  7. Java常见问题(1)navicat连接mysql报2059错误
  8. 【转】横向扩展与纵向扩展
  9. 搭建IntelliJ IDEA+maven+jetty+SpringMVC 开发环境(一)
  10. Error: Cannot find module ‘webpack-cli/bin/config-yargs‘ 解决办法
  11. LINUX SHELL如何递归访问目录(处理包含空格的文件名)
  12. 微信域名防封接口开发
  13. 打印九行菱形php,c语言打印菱形
  14. 遥感领域旋转目标检测OBB记录
  15. 服务器和交换机物理连接_交换机发生网络通信故障怎么解决?
  16. Java实现PDF打印的解决方案
  17. 安卓Andriod使用入门(二)【高仿安卓微信6.0】
  18. 图像处理之基础---去污算法
  19. 3.4 jest使用pug
  20. java 计算星座算法,java 依据生日计算星座

热门文章

  1. HIT 大物实验 数据处理代码
  2. 每日一题-特效药申报题解
  3. 面试必问之JVM原理 1
  4. Selenium2学习(四)-- xpath定位
  5. Windows nc命令下载使用与使用bash建立反弹shell
  6. Math.sin() 与 Math.cos() 用法
  7. Datawhale数据挖掘 数据分析笔记
  8. 从端到云——工业物联网项目全栈快速开发
  9. 计算思维及其培养方式
  10. Idea在Maven项目中使用支付宝沙箱环境