基于 appium 编写的自动化测试工具。使用方法简单,编写 yaml 文件格式的测试用例即可,无需改动任何一行代码。支持 Android,多台设备并行,性能采集等。
开源地址:https://github.com/ztwo/Auto_Analysis
执行编写 yaml 格式的 testcase,执行后即可得到测试报告
字段 | 解释 | 演示 | 包含字段 | 是否必须 |
---|---|---|---|---|
test_name | 用例名 | login | / | 是 |
test_id | 用例 id | 0001 | / | 否 |
test_control_type | 查找控件方式 | xapth | xpath, id | 否 |
test_action | 操作方法 | click | 见下表 | 是 |
test_control | 控件 | com.xx.id | / | 否 |
test_text | 断言、输入文本 | test | / | 否 |
test_inherit | 继承用例名 | login | / | 否 |
test_range | 循环本步骤次数 | 2 | / | 否 |
test_sleep | 步骤执行后,等待秒 | 2 | / | 否 |
test_wait | 配合断言,等待控件秒 | 30 | / | 否 |
test_action | 解释 | 所有字段 | 配合字段 | 辅助配合字段 |
---|---|---|---|---|
click | 点击 | click | test_control_type,test_control | / |
send_keys | 发送文本 | send_keys | test_control_type,test_control,test_text | / |
swipe | 滑动 | swipe_left,swipe_right,swipe_up,swipe_down | / | / |
assert | 断言 | assert | test_control_type,test_control,test_text | test_wait |
entity | 实体按键 | entity_home,entity_back,entity_menu,entity_volume_up,entity_volume_down | / | / |
---
-
test_name: 点击跳过
test_id: 0001
test_control_type: id
test_action: click
test_control: test.joko.com.myapplication:id/button1
-
test_name: 输入帐号名
test_id: 0002
test_control_type: id
test_action: send_keys
test_control: test.joko.com.myapplication:id/editText
test_text: 199999999
-
test_name: 输入密码
test_id: 0003
test_control_type: id
test_action: send_keys
test_control: test.joko.com.myapplication:id/editText2
test_text: 9999
-
test_name: 点击登录
test_id: 0004
test_control_type: xpath
test_action: click
test_control: //android.widget.Button[contains(@text,'确定')]
-
test_name: 向上滑动页面
test_id: 0005
test_action: swipe_up
test_range: 3
-
test_name: 向下滑动页面
test_id: 0006
test_action: swipe_down
test_range: 3
原理:开启 appium driver,解析 yaml 格式 testcase,执行,输出报告
po.BasePage:封装 appium driver 方法
def send_key_event(self,arg):
"""
操作实体按键
:return:
"""
event_list = {'entity_home':3,'entity_back':4,'entity_menu':82,'entity_volume_up':24,'entity_volume_down':25}
if arg in event_list:
self.driver.keyevent(int(event_list[arg]))
def get_all_case(self, path_yaml):
"""
:param path_yaml: 用例地址
:return: 返回yaml内字典,且遍历继承的信息,支持多重继承
"""
def get_case(path_yaml):
case_list = []
inherit_case_file = public.GetCase.case_yaml_file()
with open(path_yaml) as f:
for dic in yaml.load(f):
if isinstance(dic, dict):
if 'test_inherit' in dic:
inherit_case_name = dic['test_inherit']
inherit_case = inherit_case_name + '.yaml'
if inherit_case in inherit_case_file.keys():
case_list += case_list + get_case(inherit_case_file[inherit_case])
else:
case_list.append(dic)
else:
U.Logging.warn('get_case:not dic')
return case_list
return get_case(path_yaml)
def __analysis_yaml(self, path_yaml):
"""
测试用例解释器
:param path_yaml: 测试用例地址
1:每执行一条用例会记录下当前的性能
:return:
"""
def phone_screen(self, width_height, filename):
"""
截图
:param width_height: 宽高
:param filename: 存储的文件名
:return:
"""
U.Logging.info('phone_screen:%s' % width_height)
self.adb.shell(
"'LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P {}/0 -s > /data/local/tmp/{}.png'".format(
width_height, filename))
U.Logging.info('phone_screen:success')
def last_update_time(self):
"""
查询当前屏幕应用安装更新时间
"""
for package in self.shell(
'dumpsys package %s' %
self.get_current_package_name()).stdout.readlines():
if 'lastUpdateTime' in package:
return package.split('=', 2)[1].strip()
def wifi_name(self):
"""
查询连接wifi名称
"""
for package in self.shell('dumpsys wifi').stdout.readlines():
if package.startswith('mWifiInfo'):
wifi_name = re.findall(r'SSID:([^"]+), BSSID', package)
if not wifi_name:
return None
else:
return wifi_name[0].strip()
lib.Utils:封装的一些基础方法,如创建数据库,log 输出等
public.installApp:安装应用,且同时开启线程,监控屏幕是否有需要点击的安装按钮
def main(self):
"""
开启多线程:
线程1:安装应用
线程2:获取当前页面是否有可点击的按钮
:return:
"""
ini = U.ConfigIni()
install_file = ini.get_ini('test_install_path', 'path')
package_name = ini.get_ini('test_package_name', 'package_name')
threads = []
click_button = threading.Thread(target=self.tap_all, args=())
threads.append(click_button)
install_app = threading.Thread(
target=self.__install_app, args=(
package_name, install_file))
threads.append(install_app)
process_list = range(len(threads))
for i in process_list:
threads[i].start()
for i in process_list:
threads[i].join()
self.adb.shell('"rm -r /data/local/tmp/*.xml"')
谢谢分享
—— 来自 TesterHome 官方 安卓客户端
@lose 跟你框架功能差不多,综合学习一下
@joko python setup.py install 执行这个步骤失败了,怎么回事呀。
之前的 appiumbooster 也是这样实现的 你们可以交流下
@seveniruby 我没安装 pip。我安装试试。谢谢你的解答思寒
这个厉害,测试报告也很漂亮
#5 楼 @seveniruby python demo_run.py 运行这步骤后报了这个错,是什么原因呀。?
图片在此
@Jhon 我跟你图片一样的结果,原因是我没开启 usb 调试工具,在手机中的 开发人员选项里。开启后 还要到门口允许这个电脑 usb 调试,就不报这个错了。
#5 楼 @seveniruby 这个为什么没有设置为精华帖啊,目录结构比较清晰,封装也很不错,值得学习。嘿嘿,强烈建议设置为精华帖,让更多的人可以学习到。支持@joko
为什么我就不能造出如此好轮子?不开心。
@joko 我用的 python3.4,调试到这步了,报这个错,还需要设置什么呢?configparser.NoSectionError: No section: 'minicap'
加精理由: 写的详细. 设计优秀. 期待以后继续改进造福大家.
#18 楼 @a_little 目前不兼容 python3,不过从报错原因来看是因为 configparser 没获取到 minicap 的绝对路径,你可以直接手动配置 data/test.ini 文件。配置说明你可以看 doc 内的 parameter_configuration.md。把里面所有的字段都给手动配置了。
#21 楼 @Jhon 没访问到包,你也手动配置 data/test.ini 的参数信息后,然后运行 po.integration.py。这是单线程的方法,可以获取到更详细的报错信息
我在 windows,linux,macos 上都运行测试过,所以大多错误应该是环境的问题,可以看项目里写的详细文档
建议 Python 新手首次运行使用 pycharm,用强大的 ide 如同老师可以帮你处理很多事情。
@joko 好的。我也是用的 python3,没想到是这个的原因,嘿嘿。感谢你的分享,我觉得很有创意。
写的挺好的👍
这段代码,直接随机生成端口,感觉会有冲突的问题啊,是不是应该增加一个端口检测是否占用的方法
@joko
支持分享
求指教,没有接触过自动化测试工具,如何入门 appium,网上很多资料都是互相转载的甚至都没经过亲身验证,实际帮助不大,想请教有经验的人指点一下,如何制定学习策略
@joko 好呢,多谢分享呀,百度了这个错是 python2 和 3 的编码不同引起的,试着解决还没果
这个报错跟我安装的 appium 版本有关系么。 我的版本是 1.4.16 !!!请大神指教,!!在线等
我想问下你的 “执行过程中会被异常打断,目前已经捕获这些异常,增加了判断” 这个是怎么实现的
先顶后看。
@joko 我也想知道你的异常怎么捕捉的,比如三台手机,有两台手机闪退了,如何捕捉到这两台闪退手机的日志信息并且在不影响到框架的正常运行的?
#24 楼 @seveniruby 提个问题 :本篇标题太长 首页看不出是精华 钻石没了
#48 楼 @410637312
#50 楼 @lose
设计框架的时候需要考虑到这些,用的是单例模式,每个线程不会互相影响。关于错误的捕捉:
1.来看代码,解释器方法包裹了一个错误捕捉器。用来捕获执行成错误的原因
def e():
"""
捕获用例执行函数异常安装
:return: True|AssertionError|AttributeError
"""
def E(func):
def wrapper(*args, **kwargs):
error_msg = True
try:
return func(*args, **kwargs)
except AssertionError as e:
U.Logging.warn(traceback.format_exc())
U.Logging.error(e)
error_msg = 'Assertion error'
except AttributeError as e:
U.Logging.warn(traceback.format_exc())
U.Logging.error(e)
error_msg = 'Attribute Error'
except Exception as e:
error_msg = traceback.format_exc()
U.Logging.error(e)
finally:
return error_msg
return wrapper
return E
@e()
def __analysis_yaml(self, path_yaml):
pass
2.错误日志的捕捉
def logcat(self, log_path):
return self.adb('logcat -v time > %s&' % (log_path))
class Anl:
def __init__(self, all_result_path):
self.all_result_path = all_result_path
@U.l()
def __log_file(self, all_path_result, the_suffix_name):
"""
:return: 日志列表
"""
return GetFilePath.all_file_path(
all_path_result, the_suffix_name).values()
def analyze(self, log_file):
"""
过滤Exception到log文件夹内
:param log_file: log的路径
:return:
"""
errorId = 0
go_on_id = 0
log_filter_name = os.path.split(log_file)[1].split('.')[0]
with open(self.all_result_path + '/log/{}filter.log'.format(log_filter_name), 'w') as s:
with open(log_file) as f:
for line in f:
if 'Exception' in line:
go_on_id = 1
s.write('#' + '-' * 40 + '\n')
s.write(line)
errorId = line.split('(')[1].split(')')[0].strip()
elif go_on_id == 1:
if errorId in line:
s.write(line)
else:
go_on_id = 0
def main(self):
"""
获取log,生成filter log
:return:
"""
for log_file in self.__log_file(self.all_result_path, '.log'):
self.analyze(log_file)
这样执行过程中的异常和错误的异常均能捕捉,查看报告即可
厉害了
想请教大家一个问题,appium 在做安卓 app 自动化测试时,点击 h5 页面 js 弹框按钮,执行的时候没有效果也不报错,为什么呢
代码是这样写的:driver.findElementByXPath("//android.view.View[contains(@content-desc,'返回修改')]").click();
通过 inspector 获取的元素内容如下
就连点击坐标也没有用
好好学习
怎么一直停在这里不运行了呢。Appium Server 要开启么。
@joko 你好,请问这个路径中的{ }大括号用意是什么呀,百度了半天无解,只好来咨询你,看起来是多选的意思,在这个路径下的多个文件,是这样的意思吗?minicap_path = /Users/joko/Documents/Auto_Analysis/data/minicap/bin/{}/minicap
安装后后报错,为什么呢
安装测试的 apk 后就一直不动了
#61 楼 @xiaocong168
#57 楼 @JeffLiu
这个问题都是因为 appium 没起来,你们要是方便的话重新拉取下 github 最新的提交,我在这块加了写 log,用于分析问题
#63 楼 @xiaocong168 不需要手动打开,代码里已经用命令方式开启,我在最新的提交里加了启动的日志,你再失败的话,把日志贴出来看看
@joko ,我和 61# 一样的错。已安装你的最新版了。日志也没记录啥呀。Appium server 还是不能启动。
appium 启动确实有问题
@joko ,
Run 程序会抛出这个异常。能简单介绍下运行原理么。
我是 mac 环境,按照教程运行的很顺利,但是在最后生成报告的时候,没有 html,其他的截图什么的都有,唯独没有 html,请问是怎么回事呢?在 demo 运行的最后,报了这么堆异常:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 801, in bootstrap_inner
self.run()
File "/Users/shiwei/Desktop/Auto_Analysis/run.py", line 30, in run
a.case_start()
File "/Users/shiwei/Desktop/Auto_Analysis/po/integration.py", line 147, in case_start
self.analysis(yaml_name, yaml_path)
File "/Users/shiwei/Desktop/Auto_Analysis/po/integration.py", line 126, in analysis
return s.main()
File "/Users/shiwei/Desktop/Auto_Analysis/po/ExecuteCase.py", line 313, in main
self.save_android_result()
File "/Users/shiwei/Desktop/Auto_Analysis/lib/Utils.py", line 125, in wrapper
t = func(*args, **kwargs)
File "/Users/shiwei/Desktop/Auto_Analysis/po/ExecuteCase.py", line 131, in save_android_result
r.main()
File "/Users/shiwei/Desktop/Auto_Analysis/public/GenerateReports.py", line 131, in main
self.device_info(),
File "/Users/shiwei/Desktop/Auto_Analysis/lib/Utils.py", line 125, in wrapper
t = func(*args, **kwargs)
File "/Users/shiwei/Desktop/Auto_Analysis/public/GenerateReports.py", line 65, in __device_info
return 'device_name:' + self.adb.get_device_name(), 'disk:' + self.adb.get_disk(), \
TypeError: cannot concatenate 'str' and 'NoneType' objects
复制的 log 不太好认,这是截图
我照着错误提示,把 return 的参数类型强转成 str 就不报错了,html 出来了
报告简洁明了,确实不错,我更想了解的是工具的实用性和内涵:
1.UI 频繁变动,如何解决维护成本问题;
2.性能图的 cpu 和 memory 能给前端性能分析带来哪些有用的价值;
3.日志能否记录下有助于开发定位问题的上下文(logcat 的错误关键字过滤,只用 exception 吗);
#78 楼 @gmjdadk 未来会支持,短期之内(二个月)不会支持
1:书写用例的方式已经极低了压缩撰写用力的的成本。
在用例层只需变更用例的继承名即可。
2:cpu 与内存我觉得是报告里最有价值的东西,横向对比可分析出迭代后相同模块的性能异常问题,通过性能异常可深入追查代码层面异常,举个实际的例子:本次此用例业务内优化了加载的方案,从用户无法明显感知,所以就要从性能入手,确认优化效果
3.关于日志过滤只有 exception,大部分异常其实只能通过 debug 日志才看出,目前没有有效的方式处理,之后可能会增加关键词过滤
@joko ,执行 python demo_run.py 这个, 是如何运行 Appium 的。运行 Appium 时候,是怎么调用 testCase 并输出报告的。Python 小白,没看明白,望楼主指点一二。
今天又遇到了另一个问题,我用命令行运行一点问题没有,换成 pycharm 运行,总是获取不到手机设备 [Error]:the computer is not connected to any devices 我打断点也看不出什么,好郁闷
@joko 如果使用 id 定位找到的是一个元素组,想点击其中一个,testcase 应该怎么写呢?不考虑 xpath
在 win7 系统执行到下面就报错了。求教!
我这两天调试了一下,似乎是 pycharm 的 fork 问题,所有的 subprocess.Popen 都创建不了子进程,无奈放弃,只能用命令行运行了
稍微修改了下 html 的生成代码
请问不执行 testcase 中全部用例,执行其中几个或一个时,要怎么改
install_info = self.adb.install_app(app_file_path).stdout.readlines();
print ("hehehehehehehhehe" + install_info[-1]);
if 'Success' in install_info[-1].strip():
请教楼主在之前的代码里,针对某些机型,上述代码会报错,但是把 stdout 改成 stderr 就不会错了,
还有一个问题就是,拉取了最新代码之后
return 'device_name:' + str(self.adb.get_device_name()), 'disk:' + str(self.adb.get_disk()), \
'wifi_name:' + str(self.adb.wifi_name()), 'system_version:' + str(self.adb.get_android_version()), \
'resolution:' + str(self.adb.get_screen_resolution())
这一段还是会报错,我就把没有加 str 转换的都加上了,就没有错了
@joko 多谢解答
@joko 请问 python3.5 能用吗?
厚着脸皮问一下前辈,没有选择 webdriver 中自带 get_screenshot_as_png() ,而使用 minicap 的考虑是哪里呢?
请问一下,用例是随机执行的吗
你好,直接运行你的 demo_run 会报错,重装失败,类似这种:[Error]:Reinstalling com.wuba.zhuanzhuan P4M0215416001124
不知道和 appium 版本有没有关系,我的是 1.4.16...
执行一次脚本 为什么会反复执行用例呢
#102 楼 @zlx_lizzy 安装 app 失败了,检查下手机安装时是不是有一些弹窗,选择确认。目前仅封装了一些常见手机弹窗的处理
#103 楼 @xiaocong168 demo 自带了两个用例,第二个用例继承上一个用例(每次执行完毕后会初始化环境)
#105 楼 @automation 感谢回复,linux 和 macos 做了处理,原因是因为 linux 和 macos 启动后会有独立的 logcat 进程,但 windows 不是(目前观察来看是这样),所以没办法单独关闭单独 logcat 的进程。windows 这部分模块没想好怎么处理
目前遇到的问题是,运行 demo 脚本会自动打开 APPIUM 但是不会自动启动 server,然后也无法继续执行下一步。关闭 appium 就会报错。配置应该都 OK 的啊,APPIUM 版本 1.4.16 win10 64 位系统。appium 是手动安装的,环境变量也都设置了,就是图中的情况,貌似是侦测不到设备?APPIUM 也没有自动开启服务。
备注: 使用 RF+APPIUM 的方式是可以跑起来并运行一些 RF 上的 case 的。
@joke 什么时候兼容 python 3,期待大神多发帖,多分享
@joko ,
设置这 minicap_path,minitouch_path,minicapso_path 有什么用么。是用到 STF 了么。
HI @joko 感觉这里是不是有个逻辑问题
device_list = po.integration.get_device_info() 拼装当前历史已存在的 test_info and test_device 信息
capublic.GetDevice.set_device_yaml() 是获取当前设备信息并保存到 yaml
run_deviced 时候应该是当前最新的设备信息
不知道我理解对不对?
大神们,在 win7 系统执行报错,求教!
appium :1.4.16
python :2.7
device:nexus 6P
Android:7.1.1
#113 楼 @slideplustest 运行 appium-doctor 检查下环境有没有问题
#114 楼 @xiaocong168 还是不行,appium-doctor 运行结果图如下,不知道怎么搞了
#112 楼 @xiaocong168 你好~感谢反馈。这块逻辑的确不严谨,我已经修改,晚些时候提交一下,谢谢!
#113 楼 @slideplustest 错误提示里写的是 unicodeIME 安装失败,这个是 appium 的输入法,执行的时候看下手机,点下按住确认
#116 楼 @joko Hi joko 谢谢你的提示! 感觉不是 unicodeIME 安装失败的原因,重新运行了下,从提示上看是说这个 apk 已存在, 我手动 -r 强行安装完成后,运行还是说 Failure [INSTALL_FAILED_ALREADY_EXISTS: 完成错误截图如下:
看到还有一个错误的信息:"message":"A new session could not be created. 不知道跟这个是不是有关系,我再查下看看。
另外我执行后,设备上没有出现需要确认的弹窗,只是安装了 unlock/appium settings/Auto Analysis,不知道得到这样的结果对不对,有点懵~
厉害!
学习了。
—— 来自 TesterHome 官方 安卓客户端
想问下你的多设备并行是怎么做的
—— 来自 TesterHome 官方 安卓客户端
如果前面的测试执行没有通过不会对后面的操作产生影响吗?
@joko 请教个问题
login.yaml --登陆用例
other.yaml --其他业务用例
logout.yaml -退出用例
以上三个用例在同一个文件夹下,其中 other.yaml 前面继承 login.yaml,后面继承 logout.yaml
运行时会执行 login.yaml 和 logout.yaml 一次,在 other.yaml 又会再再次运行
针对这个场景其实我主要目的是重点"其他业务用例",对于 login 和 logout 只是一个初始化和退出的过程,在执行 other.yaml 业务场景时运行一次即可。
这里是不是可以调整下,可以更灵活的组织用例呢?
#122 楼 @potato 你好,只处理下多进程执行资源占用问题,查找 device,分配端口,剩下直接开启多进程执行代码即可。没有特别的处理
#124 楼 @yang_young 每个用例执行完毕后,会初始化环境(清除应用数据),不过如果服务端数据在上一用例有变更,目前框架层面没给解决,需要你独立出两套用例,或者你加个脚本,通过接口清理数据
#125 楼 @xiaocong168 明白你的意思。以用例层面实现单元测试内的 setup 与 tearDown,目前用例组织形式仅实现了 setup。按照目前框架已经实现的功能,你的用例应该这么写,other 继承 login,logout 继承 other。最近我会实现 tearDown 方法,到时候就能初始化话就和销毁环境了,不会向现在这么复杂。实现完我 @ 你
#126 楼 @joko setup 与 tearDown 你那里写好了么?我试着写了一个自己方案,在用例文件夹里建立 setup.yaml tearDown.yaml
case_start() 时候过滤这两个文件
test_case_yaml_temp = public.GetCase.case_yaml_file()
test_case_yaml_temp.pop('setup.yaml')
test_case_yaml_temp.pop('tearDown.yaml')
test_case_yaml = test_case_yaml_temp.items()
然后在 get_all_case 再拼装 setup 和 tearDown 步骤,这样用一个流程下来也没问题,不知道还有没有更好的方案呢?
这个很好,如果做成 excel 格式,然后一个固定格式,如点击,然后你需要选择 resID,在填写 ID 是多少,这样直接可以让测试小白用了。
在项目中实践了下,项目中或多或少都会用到 if esle 这样的逻辑,符合条件才执行某些分支,能把这个加上就更好了.
或者在用例中在加个一个标记 比如 test_xxx:True 如果为 True,这个步骤执行结果不影响下面其他步骤执行
@joko 请教一个问题,你调试过 IOS 的多进程么?多台设备都是使用 WDA 的 8100 这一关端口么,还是用不同的端口?
厉害了,今天试了一下,很简易实用,特别是用例编写这块。作为伸手党,在此表示感谢了
感謝,期待兼容 Python3 的版本~
@joko 执行 Demo 报错,list index out of range 数组越界了。。
@joko 谢谢你的工具,你的 demo 可以运行,可是当我换了自己的包,报错:2017-02-16 20:49:24 [Error]:Failed to start appium :Message: An unknown server-side error occurred while processing the command. Original error: Error occured while starting App. Original error: Permission to start activity denied.
2017-02-16 20:49:24 [Error]:Try restarting the appium :5DYTG6DIVWEQT849,Trying the 1 frequency
是什么原因呢???
楼主你好,请问 case 执行的顺序是怎么样的? 现在有个场景是这样的,我执行了部分 case 之后,其中一条 case 是退出当前的 app,需要重启 app?
楼主大大你好,想问下,如果我所有的 testcase 全写好了,但是运行的时候有部分 case 不想执行应该如何操作,你的执行顺序如何控制,目前只是通过继承关系。
@joko joke 兄想请问下,如果在你现在代码基础上,什么不做修改,如果我 testcase 建了多个目录,目录中有多个 case 那么我的执行顺序什么样的,遍历顺序按字母顺序来还是什么。不怕见笑我对 python 刚入门,有的还不能完全看懂。。
你好,改造 GetFilePath.py 内的函数即可实现。没现实顺序执行的原因:遍历的路径加入字典后,变为了无序状态,所以未顺序执行,你可以改造下这个函数
@joke 好的,谢谢啦,我周末已经改造好了。用起来还是很方便的
马克一个 感谢楼主啊
@121miao 多台手机一起执行啊
@121miao 他用的字典,你改为 OrderedDict 有序字典,至少就可以按字母顺序执行了。具体需求你可以根据你所需要的执行顺序更改 GetFilePath.py 这个文件哈
同样实现了 js 版本的自动化测试工具 sptt,设计理念和本文大同小异,对此有兴趣的同学可以联系我哈
@FFMS 根据提示啊 没有找到 ConfigParser 模块
@121miao 应该不是 bug,作者用了一个修饰器来捕获异常,默认作者返回了 true,当不出现任何异常的时候,当遍历 yaml 文件中每一步操作时,如果遇到异常或者 AssertionError 和 AttributeError 时会捕获到,并返回出去。
作者只是给了一个整体框架,1 个月前我还从未学过 python,就在作者的这套框架上边学边做边改,带着问题去查,能学到不少东西。
你好,你的问题是装饰器捕获了异常,但在报告结果内未展示异常显示的是 true?
请问你是用的什么工具共享的屏幕呀?
请问你是用的什么工具共享的屏幕呀?啊
不能用操作层来判断用例的状态,需要用断言来验证,一个完整的用例是需要有断言存在。
问题 1:你说的找不到控件指的是:业务条件不允许使用以控件断言,还是因为业务的变动,此控件不存在?第一种:目前只支持控制属性断言,如果想增加新的可以在 ExecuteCase.py 内增加方法。第二种:如果相关控件的消失,或者控件文本变化,用例会执行失败的
问题 2:问题我在上一个回复回答过了。用例的操作不能作为成功失败的验证,验证需要断言。举个实际例子:1:输入帐号,2:输入密码,3:登录,4:验证登录页面。操作和断言是两个事情。不过如果你确实有操作失败就报错的需要,可以改下代码:BasePage.py->find_element,把这个函数的 try 去掉即可
你好,本人小白 请问有长按、双击、点击拖拽这些 test_action 吗?
@joko 请问大大这个报错是怎么回事?如何解决 谢谢
selenium 新版问题,退回老版本即可:https://github.com/appium/python-client/issues/162
请问 #61 的问题怎么解决?appium 不能自动启动
@xiaocong168 请问你 #61 的错误是怎么解决的
@joko 为什么最多同时连接 6 个手机?有这个限制的作用是?
你好,运行过程中经常会卡住,没有报错,没有超时,比如上一步骤执行成功之后,然后就没有日志输出,感觉像终端都一起卡死了一样不清楚什么问题,关闭终端重新打开又不卡了,或者又在其他步骤后面不动了,这种可能是什么原因呀
请问您现在还在维护吗
您好,请问这里面比如有 3 个相同 id 的控件,这种以数组形式存在的 id 如何输入呢
维护,端午节有时间我更新一下,class name 的实现方式。卡住的问题你方便的话我日志发我邮箱,邮箱在 setup.py 里
@joko 请教下,我执行 demo_run.py,server 不会自动启动,而且我手动启动 server 后,python 脚本也一直不执行,什么输出都没有。谢谢了呢
找到原因了,是因为我有 appium 的快捷方式,代码里执行 appium 命令的时候会把客户端启动,但是不是 launch server 导致程序无法继续。后来删了快捷方式,命令执行就正确了。
因为 adb shell dumpsys display | grep PhysicalDisplayInf 出来的数据为空,我也遇到这个问题,把 PhysicalDisplayInf 改为 DisplayDeviceInfo 就 ok 了
@joko 最近在看你的框架,发现多设备并行执行的时候,怎么处理不同的账号登录类似这样的场景??
@joko 请问一下,没有跑起来,出现了这个异常
感谢,问题已经找到,我把 Utils.py 里面的 cmd 方法中的 close_fds=True,改成了 False,可以跑起来了,不过不知道会不会有什么不好的影响
hello,还是我,看了你的源码,发现你获取性能指标类似 cpu,men 是每执行一个 action,就是一个动作才去获取一次的,是这样吗,如果改成 sleep(1)然后获取,然后累计的数据量可能比较大,这样生成性能的折线图片是否会有问题尼??
是每一个步骤获取一次,每次获取一个数值,加 sleep 并不会获取累计的数据,没什么影响。不过别这么做,操作后立即获取得到的数据比较能反应性能状态,等待 1 秒后,可能已经回落
你好,请问这个抓取的性能指标是通过什么接口做到的,能都详细介绍下
@joko 看了你的源码,真乃大神也, 进程 线程 装饰器 形参 位参。。。。 adb 封装一句搞定。
logging 使用出神入化。。。 代码规范完全符合 google 工程级标准。
求继续维护,支持 h5 支持 ios 和 支持设备管理 等其它功能
楼主你好,我被这个问题困扰好久了,找答案也没找到可靠的,请问你有解决的办法吗
万分感谢啊,楼主,哈哈哈
@joko 不知道你还会不会回帖,我遇到了这个问题。运行时直接卡在这里不运行了,有时候可以运行成功但是会一直提示找不到 dump.xml 这个文件
这些文件夹只有关闭运行的时候才能生成,并不是实时生成的,不知道什么原因
楼主,能留个联系方式嘛。。。有点问题请教
你好,请问 yaml 里面怎么设置多个检查点?
@joko 楼主好,我这边遇到用例中的测试步骤总是执行完第一个就不会再往下执行的情况,比如截图中的首页列表页滑动 2 用例执行完后就不再执行首页列表页滑动 3 了,麻烦帮忙看下。我使用的是我们自己的 app
楼主,我写的动态申请权限自动点击,点击完第一个允许后,点击第二个允许就一直不执行,没收到这个命令,不知为什么
楼主,vivo 手机用 adb 安装的时候,需要确认才能安装,你在 adb 安装的时候,调用 self.uidump() 获取页面的 xml 文件,但是 adb install 的时候用 adb shell uiautomator dump 是不能同时使用的,所以无法获取到安装确认页面,一直提示 “2019-08-15 15:34:33 [Success]:installApp:element, return:None”,所以一直装不成功
还想教下楼主,button5 = 'vivo:id/vivo_adb_install_ok_button'这个 button 的 id 是如何获取的呀?