ATX 某 APP 跑步模块性能测试

不二家 · 2017年09月28日 · 最后由 昨天有雨 回复于 2020年10月20日 · 4894 次阅读
本帖已被设为精华帖!

背景

需要实现跑步性能测试,我们的实现流程是安卓开发单写了一个类似于小熊快跑的 app,这个 app 的唯一功能是解析 gps 文件,然后快速模拟定位,然后打开某 APP 跑步模块,就可以模拟跑步了,由于在 release 版本内关闭了模拟定位的功能,只在 debug 包内支持模拟定位跑步的功能。这样实现流程就简单了。

graph TD
安装模拟GPSAPP-->传入GPS文件
传入GPS文件-->启动APP跑步模块
启动APP跑步模块-->记录手机端的性能数据
记录手机端的性能数据-->分析报告

关键点

里面涉及到几个关键实现的点,我一一列举一下。

1、启动模拟跑步 APP 和 APP 跑步模块

很久之前,写过 Appium 的自动化测试,但是这次准备用 atx。

因为之前写 iOS UI 自动化的时候接触过 atx,atx 即封装的 webdriveragent,和 uiautomator。

pip install --upgrade --pre atx --user -U

pip install opencv_contrib_python --user -U

官方文档提供了一些简便的 api,由于我只当前只关注 Android,其实我对 iOS 更熟悉,因为之前在研究 python-wda 源码的时候也有过一点点的贡献。

话不多说,上代码。

首先,在安装好 atx 以后可以检查一下环境和当前的版本:

python -m atx version
# 检查环境配置是否正常
python -m atx doctor

还好,都是正常的。

这个时候,我从 Jenkins 构建拿到了两个 APP,分别是 APPDebug 版本和模拟跑步 APP。

先用 atx 支持的命令取得 app 的包名和启动 activity 名字

举其中 GPS.apk 的例子。

python -m atx apkparse GPS.apk
{
    "version": {
        "code": "1", 
        "name": "1.0"
    }, 
    "main_activity": "com.FakeGPXActivity", 
    "package_name": "com.fakegps"
}

取到 packagename 和 activity 之后,就可以启动 app 然后进行一系列的操作了。

## 启动模拟 GPS数据app

import atx

self.driver = atx.connect()
self.driver.start_app("com.fakegps", "com.FakeGPXActivity")

2、获取手机端的内存和 PSS 值

对于如何获取手机端的性能数据,testerhome 里面有很多这方面知识的描述,我简单描述最后如何放在启动 APP 和执行点击操作的调用。

是通过异步的方式,先在启动 APP 前,初始化获取数据的线程,然后在执行操作的命令前,结束数据的获取。

因为在给 Flask 增加单元测试中,当时接触过 Python 的几个测试框架,对 Nose 最有好感,最后用例的编写是通过 Nose,启动,直接通过 nosetests 即可。

import atx
## 这里是封装的取Android性能数据的部分代码
from cpu_mem_log_thread import CpuMemLogThread

packagename = 'com.xx'
activity = 'com.xx'
packagename_gps = 'com.xxx'
activity_gps = 'com.xxx'
filename = 'perftest.log'


class test():
    def setup(self):
        self.driver = atx.connect()
        self.driver.start_app(packagename_gps, activity_gps)
        self.driver.sleep(5)
        self.driver.start_app(packagename, activity)
        self.log_thread = CpuMemLogThread(packagename, filename)
        self.log_thread.start()

    def teardown(self):
        self.exit_run_module()
        self.log_thread.stop = True

        self.driver.stop_app(packagename)
        self.driver.stop_app(packagename_gps)

    def exit_run_module(self):
        self.driver.click_exists(resourceId='running_button_change_mode_to_normal')

        self.driver(resourceId='pause_button').long_click()

        if self.driver(resourceId='finish_button').exists:
            self.driver(resourceId='finish_button').click()
        else:
            raise Exception(u"出错了,没有结束按钮")

        # print self.driver.dump_view()
        self.driver(text=u'确定').click()

    def test_run(self):
        self.driver.sleep(5)

        self.driver.click_exists(text=u'运动')
        self.driver.sleep(2)
        self.driver.click_exists(text=u'继续')
        self.driver.sleep(5)
        if self.driver(resourceId='running_button_change_mode_to_normal').exists:
            self.driver.click_exists(resourceId='running_button_change_mode_to_normal')
        else:
            raise Exception(u"出错了,不在跑步地图界面")

        # 这里我们默认让app模拟跑3个小时
        self.driver.sleep(10800)
        self.driver.screenshot('run_end.png')

nose 执行的时候会先调用执行 setup,在用例结束执行之后,会调用 teardown,所以把 setup 中放入了启动 APP 应用和开始执行性能数据抓取的动作,而在 teardown 中放入先停止执行性能数据抓取操作,最后 stop app 之前启动的 APP。

具体的执行命令是:

nosetests -v run.py --with-xunit

3、跑步性能测试的报告

单独配置了一个 html 模板,然后解析 nosetests.xml,加上截屏和 perf.log,作为数据参数。

然后通过 jinja2 传入 html 模板,然后生成报告,最后报告的样式如下:

后续

当我真正把这套流程部署在 Jenkins 上的 slave 以后,总是会出现,手机和 mac 连接不稳定的情况出现,当我都要放弃的时候,@codeskyblue提出已经升级了uiautomator2, 运行更加稳定同时也支持无线连接,也的确不在想重新配置 appium 环境,就用 uiautomator2 去解决 atx 稳定执行的问题

使用新的 uiautomator2 库

配置环境

git clone https://github.com/openatx/uiautomator2
cd uiautomator2

# 用当前用户权限安装
python setup.py install --user --prefix=

https://github.com/openatx/atx-agent/releaseslinux_armv7.tar.gz下载以
结尾的二进制包。绝大部分手机都是 linux-arm 架构的。

解压出 atx-agent 文件,然后打开控制台

$ adb push atx-agent /data/local/tmp
$ adb shell chmod 755 /data/local/tmp/atx-agent
# launch atx-agent in daemon mode
$ adb shell /data/local/tmp/atx-agent -d

这里的输出一定要是 0.0.3,再继续。若有问题,建议可以 adb shell 进去对 atx-agent 执行 chmod 授权操作。

由于我的手机 ip 和 mac 的网络不在同一个网段,因而需要一个 adb forward 转发操作,当然也可以直接启动手机端的 ip,不进行转发操作。

adb forward tcp:7912 tcp:7912

这个时候分别执行

adb shell 'echo $(curl -s localhost:7912/version)'

curl localhost:7912/version

显示0.0.3,说明环境已经配置好了,这个时候更新一下之前代码:

import uiautomator2
import time
from cpu_mem_log_thread import CpuMemLogThread

packagename = 'com.xx'
activity = 'com.xx'
packagename_gps = 'com.xxx'
activity_gps = 'com.xxx'
filename = 'perftest.log'


class test():
    def setup(self):

        self.driver = uiautomator2.connect('http://localhost:7912')
        self.driver.app_start(packagename_gps, activity=activity_gps)
        time.sleep(5)
        self.driver.app_start(packagename, activity=activity)
        self.log_thread = CpuMemLogThread(packagename, filename)
        self.log_thread.start()

    def teardown(self):
        self.exit_run_module()
        self.log_thread.stop = True

        self.driver.app_stop(packagename)
        self.driver.app_stop(packagename_gps)

    def exit_run_module(self):
        self.driver(resourceId='running_button_change_mode_to_normal').click()

        self.driver(resourceId='pause_button').long_click()

        if self.driver(resourceId='finish_button').exists:
            self.driver(resourceId='finish_button').click()
        else:
            raise Exception(u"出错了,没有结束按钮")

        # print self.driver.dump_view()
        self.driver(text=u'确定').click()

    def test_run(self):
        time.sleep(5)
        self.driver(text=u'运动').click()
        self.driver(text=u'继续').click()
        if self.driver(resourceId='running_button_change_mode_to_normal').exists:
            self.driver(resourceId='running_button_change_mode_to_normal').click()
        else:
            raise Exception(u"出错了,不在跑步地图界面")

        # 这里我们默认让app模拟跑3个小时
        self.driver.sleep(10800)
        self.driver.screenshot('run_end.png')

可以看到运行明显稳定太多,而且 api 基本也没有变化。

由于 uiautomator2 库并不完善,之前还不支持 activity 和 packagename 启动,我也提了一个特别简单的 pr,可以支持 activity 和 packagename 启动。

最后

感谢@codeskyblue,他的分享,让我们可以这么轻便的去实现简单的页面点击操作的需求。

一直在探索 UI 自动化实现性价比高的方式,因为我们都知道,UI 自动化投入产出比是不高的。

但是我们需要找到一些特别的方式,比如某个模块,而且人工真的不好经常重复操作的行为,感觉这才是 UI 自动化可以有突破的点。

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

看了有点懵逼,不是很懂。

文章很偏实战,pr 也不错

有意思

思寒_seveniruby 将本帖设为了精华贴 09月29日 08:40

棒!很好的思路!学习了!

不二家 在 Android 手机内执行 UI 自动化测试 中提及了此贴 10月09日 14:57
不二家 在 Android 手机内执行 UI 自动化测试 中提及了此贴 10月09日 17:07

过程讲得非常详细,多谢分享~~

过程和坑都描述了,多谢分享

jeky2017 回复

太客气。。。

xiaoyu 回复

客气啦。。。

12楼 已删除

GPS.apk 在哪可以下啊

这觉得干活,有空仔细拜读研究一下

chma 回复

这是我们开发帮忙写的,很简单就是一直读 gps 文件,模拟定位就行,网上有小熊快跑这种类似的。

不二家 回复

我试了小熊跑步,但是我看需要 root 权限,还要装 xpose,我都没装成功,所以很想知道你那边怎么实现的,求指导

chma 回复

我实在指导不了多少,你可以找安卓开发帮忙一把,这对他们而言应该不难。我之前试过小熊快跑,只 root 了,未装 xpose,抱歉。

simple 专栏文章:[精华帖] 社区历年精华帖分类归总 中提及了此贴 12月13日 14:44
simple [精彩盘点] TesterHome 社区 2018 年 度精华帖 中提及了此贴 01月07日 12:08

请问楼主安卓单写的模拟跑步 app,iOS 上也可用吗?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册