分享一个基于 ATX-Server 的 UI 自动化测试框架,可以实现多设备的并行测试,并生成统一的测试报告 GitHub 地址:https://github.com/pengchenglin/ATX-Test
Android 设备需要通过 uiautomator2 init 初始化完成,确认可以正常连接 ,或者 init 接入 atx-server
相关的基础链接如下
小白入门篇:python uiautomator2 的代码示例
浅谈自动化测试工具 python-uiautomator2
atx 安卓集群管理 安装运行及自动化的实践
ATX-uiautomator2 实现 webview 的操作
1.下面展示的内容多源于 TesterHome 各位前辈的经验总结,我只是按照个人想法进行了简单拼接(基于 ATX-uiautomator2 的 Android 自动化测试)
2.主要参考了@hualin (王华林) 老师的https://testerhome.com/topics/7550uiautomator2 实现,并在此基础上结合
3.所用语言为 Python,测试报告模板借用了https://github.com/Gelomen/HTMLTestReportCN-ScreenShot,并进行了简单的修改以方便截图
4.使用了 macaca 的 bootstrap app 作为 demo 演示
工程目录如下
主体结构和@hualin (王华林) 老师的https://testerhome.com/topics/7550 的一致,主要修改了 Pubilc 下一些东西,并增加了一些东西
Public:
下面介绍一下流程:
1、通过 run_cases .py 或者 run_all_cases.py 开始执行测试
if __name__ == '__main__':
# back up old report dir 备份旧的测试报告文件夹到TestReport_backup下
backup_report()
cs = CaseStrategy()
cases = cs.collect_cases(suite=False)
Drivers().run(cases)
# Generate zip_report file 压缩测试报告文件
# zip_report()
1.首先会将 Testreport 目录剪切到 TestReport_backup 目录下,备份旧的测试报告
2.通过 CaseStrategy 获取到需要执的测试用例
3.Drivers().run(cases)
开始执行测试
4.执行完成之后打包压缩,没啥用 注释掉了
2、run(cases)
执行测试
def run(self, cases):
# 根据method 获取android设备
method = ReadConfig().get_method().strip()
if method == 'SERVER':
# get ATX-Server Online devices
devices = ATX_Server(ReadConfig().get_server_url()).online_devices()
print('\nThere has %s online devices in ATX-Server' % len(devices))
elif method == 'IP':
# get devices from config devices list
devices = get_devices()
print('\nThere has %s devices alive in config IP list' % len(devices))
elif method == 'USB':
# get devices connected PC with USB
devices = connect_devices()
print('\nThere has %s USB devices alive ' % len(devices))
else:
raise Exception('Config.ini method illegal:method =%s' % method)
if not devices:
print('There is no device found')
return
# generate test data data.json 准备测试数据
generate_test_data(devices)
print('Starting Run test >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
runs = []
for i in range(len(devices)):
runs.append(RunCases(devices[i]))
# run on every device 开始执行测试
pool = Pool(processes=len(runs))
for run in runs:
pool.apply_async(self._run_cases,
args=(run, cases,))
print('Waiting for all runs done........ ')
pool.close()
pool.join()
print('All runs done........ ')
ChromeDriver.kill()
# Generate statistics report 生成统计测试报告 将所有设备的报告在一个HTML中展示
create_statistics_report(runs)
1.首先根据 config.ini 中method
的值来判断从 atx-serve 获取 online 的设备 还是从 config.ini 中的 ip 来获取在线的设备,或者直接获取连接电脑的安卓设备
2.在获取到设备之后,根据设备生产 data.json 测试数据
3.并行多设备执行测试
4.测试完之后,杀掉执行过程中打开的所有的 chromedriver 进程
5.最后在 TestReport 下生成统计测试报告(自动化测试报告.html)
生成的测试报告路径结构如下
每个设备的测试结果及报告或存放在单独的文件夹下
在 Testreport 目录下会有一个统计测试报告(自动化测试报告.html) 会将所有设备的报告统一在一个页面展示
报告展示:
method 设置为 USB 之后,手机有线连接到电脑的,就算 offline 的设备也能自动重启 u2 跑脚本了。
前提是你的 u2 要升级到 Version: 0.1.3.dev5 及以后,guthub 上更新最新的 ATX-Test 代码
因为 uiautomator2 更新了 connect_usb 方法
def connect_usb(serial=None):
"""
Args:
serial (str): android device serial
"""
adb = adbutils.Adb(serial)
lport = adb.forward_port(7912)
device = connect_wifi('127.0.0.1:' + str(lport))
if not device.alive:
warnings.warn("atx-agent is not alive, start again ...", RuntimeWarning)
adb.execute("shell", "/data/local/tmp/atx-agent", "-d")
device.healthcheck()
return device
还有个 python 第三方库 psutil
需要依赖的 python 第三方库 tinydb
、uiautomator2
、selenium
、jinja2
开源大赞
来学习下
不错不错
学习~学习~
先 star 了
学习~学习~
和 appium 结合 stf 的思想差不多
uiatuomator2 实现了 toast 的获取 请更新 u2 到最新的 0.1.3.dev2
https://github.com/openatx/uiautomator2#toast
然而
d.watchers.watched = True
有问题 可能在 0.1.3.dev3 中解决
在 CaseStrategy 里的 suite_path 和 case_path ,case_pattern 路径应该要怎样配置?配置全路径吗?
我运行时报了以下错
Traceback (most recent call last):
File "/my_work/my_work/ATX-Test-master/run_all_cases.py", line 16, in <module>
cases = cs.collect_cases(suite=True)
File "/my_work/my_work/ATX-Test-master/Public/CaseStrategy.py", line 40, in collect_cases
self._collect_cases(cases, top_dir=test_suite)
File "/my_work/my_work/ATX-Test-master/Public/CaseStrategy.py", line 16, in _collect_cases
pattern=self.case_pattern, top_level_dir=top_dir)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/loader.py", line 304, in discover
os.path.dirname((the_module.__file__)))
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/posixpath.py", line 156, in dirname
p = os.fspath(p)
TypeError: expected str, bytes or os.PathLike object, not NoneType
self.suite_path = 'TestSuite_'
self.case_path = 'TestCase'
self.case_pattern = 'test*.py'
文件夹和文件以上面的命名开头就行了啊
2018-06-26 10:20:40,943 - Redmi Note 4X - INFO - udid: c9c6d32a0804-38:e6:0a:7c:1b:20-Redmi_Note_4X
Error TestCase..pytest_cache (unittest.loader._FailedTest)
大神,这个错误是哪里的问题
测试报告不错,是不是我在 appium 框架中也能用
学习了!!
Waiting for all runs done........
2018-10-31 15:34:11,248 - huawei tag-tl00 - INFO - udid: 00b84da5--huawei_tag-tl00
All runs done........
All chromedriver pid killed
Traceback (most recent call last):
File "C:/Users/diaost/Desktop/ATX-Test-master/run_all_cases.py", line 17, in
Drivers().run(cases)
File "C:\Users\diaost\Desktop\ATX-Test-master\Public\Drivers.py", line 97, in run
create_statistics_report(runs)
File "C:\Users\diaost\Desktop\ATX-Test-master\Public\Report.py", line 66, in create_statistics_report
tmp_dic.update(_get_report_info(run))
File "C:\Users\diaost\Desktop\ATX-Test-master\Public\Report.py", line 38, in _get_report_info
with open(report, 'r', encoding='utf-8') as f:
FileNotFoundError: [Errno 2] No such file or directory: './TestReport/2018-10-31_15_34_10-huawei tag-tl00/TestReport.html'
大神,运行报这个错要怎么解决的,是哪里的路径需要改吗
你的用例没执行成功吧 TestReport.html 文件都没生成
可以直接将 ATX-Test-master\Public\Drivers.py", line 97 的 create_statistics_report(runs) 这句话注释掉好了 其实这个只是在运行完生成一个统计的报告页面罢了
@linpengcheng 单个 case 如何调试, 不能用 TestSuite() 来调试么
可以啊 这样就好了吧
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
sys.path.append('..')
from Public.Drivers import Drivers
from Public.Report import *
from TestSuite_demo.TestCase import test_01_install
if __name__ == '__main__':
# back up old report dir 备份旧的测试报告文件夹到TestReport_backup下
backup_report()
cases = unittest.TestSuite()
cases.addTest(test_01_install.app_install('test_01_install_apk'))
Drivers().run(cases)
hi,
我把 APP 的包名改成我们公司的 app,为什么启动的是 debug 的 Leaks?
我在 win10 上运行的,但是无法安装 apk,报 Exception, -32002 Client error: <> data: , method: None 错误,请帮忙看下?
目前采用 Uiautomator2 工具做 UI 自动化测试,发现经常有些异常信息出现导致程序不能正常的执行下去,所以针对这些异常,我想采用监控 app 软件是否在最上层,如果不在最上层就 home 键盘把后台进程都 kill 掉 用 python 实现?或者有没有更好的方法来处理?
另外,可以 python 实现 Uiautomator2 监听网络状态,连接指定 Wi-Fi 吗?
d.current_app()
可以查看当前页面启动的包名和 activity 名称
d.app_stop_all()
可以关闭所有的第三方安装启动着的 app
运行脚本的时候 $ python3 Auto_ota.py 为什么总是报如下警告:
C:\Python36\lib\subprocess.py:761: ResourceWarning: subprocess 14572 is still running
ResourceWarning, source=self)
Auto_ota.py:38: ResourceWarning: unclosed file <io.BufferedReader name=3>
check_ip_ping()
C:\Python36\lib\site-packages\uiautomator2__init_.py:375: RuntimeWarning: uiautomator2 is not reponding, restart uiautomator2 automatically
stacklevel=1)
.
你好,请问在你的框架基础上如何单个循环执行 cases 100 次?
是的,比如:run_all_case 用例 循环次数,以这种方式跑,可以做吗?
博主你好这里是匹配的什么呢?图片的路径吗?还有啊 image = self.REPORT_TEST_OUTPUT_IMAGE % dict(
screenshot=saxutils.escape(uo + ue) 这一部分不太懂
截图的操作会输出 htmltesterrunner 读取到输出的内容 带 IMAGE:字段的 解析出来 吧真实的图片地址添加到报告里
我用这种方式,不会打印测试案例里面的 print 或者 Logging 的东西,只打印了成功或者失败的结果。请问是怎么配置的?
testsuite 下的 csaes 的 py 文件写法和 pageobject 目录下的写法一样 log.i(xxxxxxxx)就好了
楼主您好,在执行 case 的时候,如果多个手机里面的 webview 对应的 chromdriver 版本不一样,请问这样的该怎么处理呢?
获取到手机上 chrome 的版本 然后启动 PC 端指定版本的 chromedriver
可以参考这个
https://testerhome.com/topics/15915
楼主,你好,请教个问题,为什么每次执行都会先退到桌面,相关逻辑代码可以帮忙指出吗?
还有就是每次自动化测试执行完后都会弹出下面的图片所示的界面,是否可以取消,不让其显示?
1、退回桌面应该是 setup terndown 里写脚本 cls.d.app_stop("com.github.android_app_bootstrap")
2、Public 下的 Drivers.py 94 行的 base_page.identify() 注释掉就好了
感谢楼主
"home"
操作报告里多出一条这样的记录 "W/ActivityManager( 2931): Invalid packageName: com.github.android_app_bootstrap"
请问 返回桌面(首页)
这个问题还有其它的解决办法吗?
每次执行 python run_cases.py
都会回到桌面,下面是具体代码,不知道是不是我写的有问题
具体的自动化操作相关代码
class apk_install(unittest.TestCase, BasePage):
@classmethod
@setupclass
def setUpClass(cls):
print("setupClass")
# cls.d.app_stop_all()
cls.d.app_stop("com.github.android_app_bootstrap")
pass
@classmethod
@teardownclass
def tearDownClass(cls):
print("tearDownClass")
cls.d.app_stop("com.github.android_app_bootstrap")
pass
@testcase
def test_install_apk(self):
self.d.app_uninstall(pkg_name)
# self.d.app_info(apk_url)
self.local_install(apk_path)
self.d.app_start(pkg_name)
执行操作的相关代码
cases.addTest(test_install_apk.apk_install('test_install_apk'))
Drivers().run(cases)
那我弄错你之前回复的意思了,不好意思。
我遇到的问题是:本来代码里就没有加这个 cls.d.app_stop
代码的,但是在执行 python run_cases.py
也是会退到桌面,不是杀死指定程序,而是执行了home
的操作 (推测),有什么办法可以让它不做出这样的操作呢?
我所说的执行了
home
操作的现象:
- 如果当前设备显示 app,则退回桌面(不一定是首页)
- 如果当前设备显示桌面,则滚回到桌面首页
执行 cases 前会 check_alive 里面有一个 d.healthcheck() 的方法。
def healthcheck(self):
"""
Reset device into health state
Raises:
RuntimeError
"""
sh = self.ash
if not sh.is_screen_on():
print(time.strftime("[%Y-%m-%d %H:%M:%S]"), "wakeup screen")
sh.keyevent("WAKEUP")
sh.keyevent("HOME")
sh.swipe(0.1, 0.9, 0.9, 0.1) # swipe to unlock
sh.keyevent("HOME")
sh.keyevent("BACK")
self.reset_uiautomator()
你可以注释掉 drivers.py 下 check_alive 方法下的 d.healthcheck() 的方法,但是 你运行的时候 要保证手机是不再锁屏状态的
请问这个是多设备并行 run 还是串行 run 的测试用例?
楼主刚开始看,麻烦问下 token 怎么获取的?
请问如果是 usb 链接的是不是需要把 config 里面的 method = USB 开启,其他的都注释了?
请问 ATX_Server.py 和 atxserver2.py 的区别在哪里,是分场景使用?
不知道怎么回事,我有时候用 exists 做校验,好像不准,有时候又准,还有什么其他的方法可以做校验吗?
请教下:脚本模拟单击输入框,没有弹出键盘
手动单击会弹出键盘,是 什么情况呢?
我在设备初始化 的时候将输入法切换掉了 主要是为了防止跑脚本的时候 弹出的默认输入法太长遮挡 UI
https://github.com/pengchenglin/ATX-Test/blob/master/Public/Drivers.py
请教下:push 到 data/local/tmp 路径里面的.apk 安装包,在安装包里面看不到,有什么解决方法吗?
请教下 ATX-Test 支持 IOS 手机吗?
请教下:如果公司有多个 APP 项目,是都在这个工程下面,通过测试套区分还是说每个项目独立一个工程呢?如果每个项目独立一个工程,那维护公共代码就有点不好维护了。大家是怎么做的呢?
@linpengcheng 请教下 我们这套框架在 weditor 能获取到元素,但是执行脚本的时候,经常出现找不到元素的情况。是不是因为对 RN 的兼容问题? 对原生的 app 页面 是不是更友好些?
我目前将这个项目的结构做了修改 多个 app 可以在一个项目下进行
在 weditor 能获取到元素,但是执行脚本的时候,经常出现找不到元素的情况。 是不是你用的 xpath 定位 而且是直接复制的 weditor 内的代码?
在 weditor 能获取到元素,但是执行脚本的时候,经常出现找不到元素的情况:用 xpath 和 text 或者 description 都试过,都有这种情况。xpath 基本就是直接复制的 weditor 里面的。 text 和 description 相对简单,会手动输入。
直接复制会有什么已知的问题吗?或者说和我们 APP 不是原生的有关?
xpath 每次既然怒页面 对应的相对位置可能不太一样 估计是你写的元素定位不太正确
有 text 和 description 或者 resouceid 的 建议优先使用 这几个参数来定位,或者好好了解下 xpath 定位,吧定位写的通用一点,一般就不会报 元素找不到的错误了。
weditor 定位元素 自动生成代码只是为了方便,具体的脚本还是要调试的
目前正在使用大佬的框架,非常好用
请问下,取 atx2 的设备,然后这个报错是什么情况
``py
File "D:/Projects/Python/ATX-Test-master/Demo/TestSuite_demo/run_cases.py", line 29, in
devices = check_devives(dm_config.method, dm_config.udid)
File "D:\Projects\Python\ATX-Test-master\Public\devices_new.py", line 133, in check_devives
devices = atxserver2_online_devices(atxserver2().present_android_devices())
File "D:\Projects\Python\ATX-Test-master\Public\atxserver2.py", line 139, in present_android_devices
self.refresh()
File "D:\Projects\Python\ATX-Test-master\Public\atxserver2.py", line 91, in refresh
self.purge()
File "D:\Projects\Python\ATX-Test-master\Public\atxserver2.py", line 106, in purge
self.db.purge_tables()
File "C:\Users\xxxxxxx\AppData\Local\Programs\Python\Python37\lib\site-packages\tinydb\database.py", line 255, in __getattr_
return getattr(self.table(self.default_table_name), name)
AttributeError: 'Table' object has no attribute 'purge_tables'
数据库装老版本可以了,但是后面报这个
File "D:\Projects\Python\ATX-Test-master\Public\devices_new.py", line 30, in atxserver2_online_devices
if i.get():
File "C:\Users\XXXXXXX\AppData\Local\Programs\Python\Python37\lib\multiprocessing\pool.py", line 657, in get
raise self._value
AttributeError: 'Device' object has no attribute '_filelock'
请问下 uiautomator2 的版本号是多少呢
你好,执行的时候打印日志报错,请问如何解决?
Traceback (most recent call last):
File "/Users/tester/PycharmProjects/ATX_UI_Test/Public/decorator.py", line 92, in wrapper
log.d('--> %s' % func.__qualname__)
File "/Users/tester/PycharmProjects/ATX_UI_Test/Public/log.py", line 30, in d
self.logger.debug(msg, *args, **kwargs)
AttributeError: 'Log' object has no attribute 'logger'