Appium python+appium 开源框架分享

测试小书童 · October 28, 2016 · Last by 测试小书童 replied at April 25, 2017 · 8594 hits
本帖已被设为精华帖!

介绍

  • 参数化unittest传class就可以执行class下面的所有case
  • 报告统计

    • 本地记录失败日志并截图
    • 统计所有的case和详细case的性能信息,包括men,fps,cpu使用情况
  • yaml管理所有的配置文件.只要改case配置,不用改其他代码

测试报告图片

目录分析

  • Common 主要放一些全局变量,其他公用方法
  • img 主要放一些图片,测试的app文件
  • testBLL 三层
  • testDAL 三层
  • testModel 三层
  • testRunner
    • 一个抽象入口,主要管理整个框架的setUpClass,tearDownClass,以及parametrize
    • 一个是真正的入口,调用抽象入口

配置yaml 信息说明

  • 配置case的参数介绍

  • element_info: cn.ibona.t1_beta:id/GroupPersonItemPosition

    • 主要填入的是元素的具体信息,如xpah,id,name等信息
  • find_type: by_id

    • find的类型
    find_element_by_id = "by_id"
    find_elements_by_id = "by_ids"
    find_element_by_name = "by_name"
    find_elements_by_name = "by_names"
    find_element_by_link_text ="by_link_text"
    find_elements_by_link_text = "by_link_texts"
    find_element_by_xpath = "by_xpath"
    find_elements_by_xpath = "by_xpaths"
    find_element_by_class_name = "class_name"
    find_elements_by_class_name = "class_names"
  • operate_type: click

    • 填入的操作信息
    SEND_KEYS = "send_keys" 输入
    TAP = "tap"
    SWIPELEFT = "swipeLeft" 左滑动,一般还有配置time参数(左滑次数)
    CLICK = "click"
  • text: 1111111 此参数一般与send_keys配套,表示输入的参数

  • index: 0 此参数一般与find_type配置里面的ids,names,xpaths等一组文件配套使用

  • test_id: 1003 用例id

  • test_intr: 个人反馈 用例介绍

其他说明

  • 第一部分用例是用例的开始,需要配置用例的id,介绍等信息,其他数据一样
  • 中间部分可以多个用例,不限制
  • 最后一个用例是整个用例的检查点

第一次打开app引导图检查例子

--- 
-
element_info: //android.widget.Button[@text='允许']
test_intr: 引导图
operate_type: click
find_type: by_xpath
test_id: 1001
-
element_info: cn.ibona.t1_beta:id/btn_skip
operate_type: click
find_type: by_id
-
operate_type: swipeLeft
time: 5
element_info: android.widget.ImageView
find_type: class_name
-
element_info: android.widget.Button
find_type: by_name
name: 立即开启


代码分析

入口代码

入口参数化了unittest

  • 第一层抽象入口
PATH = lambda p: os.path.abspath(
os.path.join(os.path.dirname(__file__), p)
)
def appDevices():
mapp = MAppDevices.getDriver()
return BAppDevices.appDevices(mapp, PATH("../AppDevices.ini"))
ga = appDevices()
class TestInterfaceCase(unittest.TestCase):
def __init__(self, methodName='runTest'):
super(TestInterfaceCase, self).__init__(methodName)
@staticmethod
def setUpClass():
desired_caps = {}
global driver
if ga.platformName == common.ANDROID or ga.platformName == common.IOS:
if common.FLAG:
desired_caps['platformName'] = ga.platformName
desired_caps['platformVersion'] = ga.platformVersion
desired_caps['deviceName'] = ga.deviceName
desired_caps['appPackage'] = ga.appPackage
desired_caps['appActivity'] = ga.appActivity
desired_caps['app'] = PATH(
'../img/t.apk'
)
# desired_caps["unicodeKeyboard"] = "True"
# desired_caps["resetKeyboard"] = "True"
common.PACKAGE = ga.appPackage
driver = webdriver.Remote(ga.Remote, desired_caps)
common.DRIVER = driver
common.FLAG = False
def setUp(self):
print("setUp")
@staticmethod
def tearDownClass():
# driver.close_app()
# driver.quit()
print('tearDownClass')
@staticmethod
def parametrize(testcase_klass):
testloader = unittest.TestLoader()
testnames = testloader.getTestCaseNames(testcase_klass)
suite = unittest.TestSuite()
for name in testnames:
suite.addTest(testcase_klass(name))
return suite
  • 第二层入口主要代码

# 引用需要导入的class写的case
from testCase.Home import testHome
from testCase.work import testContact

def runnerCaseApp():

start_test_time = dataToString.getStrTime(time.localtime(), "%Y-%m-%d %H:%M %p")
suite = unittest.TestSuite()
starttime = datetime.datetime.now()
suite.addTest(TestInterfaceCase.parametrize(testHome))
suite.addTest(TestInterfaceCase.parametrize(testContact))
unittest.TextTestRunner(verbosity=2).run(suite)
endtime = datetime.datetime.now()
get_common_report(start_test_time, endtime, starttime)
report()



if __name__ == '__main__':
if BAdbCommon.attached_devices():
if ga.platformName == common.ANDROID or ga.platformName == common.IOS:
appium_server = BtestServer.AppiumServer(ga.appiumJs, ga.Remote)
appium_server.start_server()
while not appium_server.is_runnnig():
time.sleep(2)
runnerCaseApp()
appium_server.stop_server()

else:
print(u"设备不存在")

看看class怎么读取yaml配置文件的case

class testHome(TestInterfaceCase):
def __init__(self, methodName=''):
super(testHome, self).__init__(methodName)
self.bc = BaseCaseList.BexceCase(test_module="个人中心", getTempCase=MBaseTestCase.getTempCase, BaseTestCase=MBaseTestCase.BaseTestCase, fps=[], cpu=[], men=[])
def home_fist_open(self):
self.bc.execCase(PATH("yaml/myinfo/home_fist_open.yaml"), test_name="test_home_fist_open", isLast="0")

def home_login(self):
self.bc.execCase(PATH("yaml/myinfo/home_login.yaml"), test_name="test_home_login", isLast="0")

def home_feed(self):
self.bc.execCase((PATH("yaml/myinfo/home_feed.yaml")), test_name="test_home_feed", isLast="1") # isLast表示的意思是最后一个case用于后面的统计
@staticmethod
def tearDownClass():
pass
# 注意这里的小技巧,这样按顺序放入case,可以按顺序执行
def test_home(self):
self.home_fist_open()
self.home_login()
self.home_feed()

execCase是所有用例class都必须用的,读取case和调用公告方法去执行所有的case,调用监控方法等

  • 这里代码比较多,很渣
class BexceCase():

def __init__(self, test_module="", getTempCase="", BaseTestCase="",fps=[], cpu=[], men=[]):
self.test_module = test_module
self.getTempCase = getTempCase
self.BaseTestCase = BaseTestCase
self.fps = fps
self.cpu = cpu
self.men = men
def getModeList(self, f):
bs = []
gh = getXMl.getYam(f)
for i in range(len(gh)):
if i == 0:
#用例id
self.getTempCase.test_id = gh[i].get("test_id", "false")
# 用例介绍
self.getTempCase.test_intr = gh[i].get("test_intr", "false")
# bt = self.BaseTestCase
self.BaseTestCase.element_info = gh[i].get("element_info", "false")

# 操作类型
self.BaseTestCase.operate_type = gh[i].get("operate_type", "false")
# 输入文字
self.BaseTestCase.name = gh[i].get("name", "false")

self.BaseTestCase.index = gh[i].get("index", "false")

self.BaseTestCase.text = gh[i].get("text", "false") # 对应by_link_text

# 验证类型
self.BaseTestCase.find_type = gh[i].get("find_type", "false")

self.BaseTestCase.time = gh[i].get("time", 0)

bs.append(json.loads(json.dumps(self.BaseTestCase().to_primitive())))
return bs

def execCase(self, f, **kwargs):
logTest = testLog.myLog().getLog()
bc = self.getModeList(f)
go = bo.getOperateElement(driver=common.DRIVER)
ch_check = bc[-1]
for k in bc:
if k["operate_type"] != "false":
if go.operate_element(k)== False:
logTest.checkPointNG(common.DRIVER, kwargs["test_name"], kwargs["test_name"])
logTest.resultNG(kwargs["test_name"], "找不页面元素")

get_men = ap.get_men(common.PACKAGE)
get_cpu = ap.top_cpu(common.PACKAGE)
get_fps = ap.get_fps(common.PACKAGE)


self.cpu.append(get_cpu)
self.men.append(get_men)
self.fps.append(get_fps)

common.MEN.append(get_men)
common.CPU.append(get_cpu)
common.FPS.append(get_fps)


if go.findElement(ch_check):
common.test_success += 1
self.getTempCase.test_result = "成功"
logTest.resultOK(kwargs["test_name"])
else:
# logTest.screenshotNG(common.DRIVER, kwargs["test_name"])
logTest.checkPointNG(common.DRIVER, kwargs["test_name"], kwargs["test_name"])
common.test_failed += 1
test_reason = "检查不到元素"
# if common.I_ANR > 0:
# test_reason = "有ANR错误"
# if common.I_CRASH > 0:
# test_reason = "有CRASH错误"
# if common.I_EXCEPTION > 0:
# test_reason = "有EXCEPTION错误"
self.getTempCase.test_result = "失败"
self.getTempCase.test_reason = test_reason

self.getTempCase.test_name =kwargs["test_name"]
self.getTempCase.test_module = self.test_module
common.test_sum += 1

self.getTempCase.test_men_max = rp.phone_max_use_raw(self.men)
avg_men = ba.get_avg_raw(self.men) # 获取每次占用内存多少
self.getTempCase.test_men_avg = avg_men
self.getTempCase.test_cpu_max = rp.phone_avg_max_use_cpu(self.cpu)
self.getTempCase.test_cpu_avg = rp.phone_avg_use_cpu(self.cpu)
self.getTempCase.test_fps_max = rp.fps_max(self.fps)
self.getTempCase.test_fps_avg = rp.fps_avg(self.fps)

common.RESULT["info"].append(json.loads(json.dumps(self.getTempCase().to_primitive())))
if kwargs["isLast"] == "1":
# 最后case要写最下面的统计步骤
common.RRPORT["info"].append(common.RESULT["info"])

上面说的是BexceCase获取case后,主要调用的是getOperateElement里面的查找元素和执行操作

# 此脚本主要用于查找元素是否存在,操作页面元素
class getOperateElement():
def __init__(self, driver=""):
self.cts = driver
def findElement(self, mOperate):
'''
查找元素.mOperate是字典
operate_type:对应的操作
element_info:元素详情
find_type: find类型
'''
try:
WebDriverWait(self.cts, common.WAIT_TIME).until(lambda x: elements_by(mOperate, self.cts))
return True
except selenium.common.exceptions.TimeoutException:
return False
except selenium.common.exceptions.NoSuchElementException:
print("找不到数据")
return False


def operate_element(self, mOperate):
if self.findElement(mOperate):
elements = {
common.CLICK: lambda: operate_click(mOperate, self.cts),
# common.TAP: lambda: operate_tap(mOperate["find_type"], self.cts, mOperate["element_info"], arg),
common.SEND_KEYS: lambda: send_keys(mOperate, self.cts),
common.SWIPELEFT: lambda : opreate_swipe_left(mOperate, self.cts)
}
return elements[mOperate["operate_type"]]()
return False

# 点击事件
def operate_click(mOperate,cts):
if mOperate["find_type"] == common.find_element_by_id or mOperate["find_type"] == common.find_element_by_name or mOperate["find_type"] == common.find_element_by_xpath:
elements_by(mOperate, cts).click()
if mOperate["find_type"] == common.find_elements_by_id or mOperate["find_type"] == common.find_elements_by_name:
elements_by(mOperate, cts)[mOperate["index"]].click()
# 记录运行过程中的一些系统日志,比如闪退会造成自动化测试停止
errorLog.get_error(log=r"d:\operate_log.txt")

def opreate_swipe_left(mOperate, cts):
time.sleep(1)
width = cts.get_window_size()["width"]
height = cts.get_window_size()["height"]
for i in range(mOperate["time"]):
cts.swipe(width/4*3, height / 2, width / 4 *1, height / 2, 500)
time.sleep(1)
# start_x,start_y,end_x,end_y

# 轻打x轴向右移动x单位,y轴向下移动y单位
# def operate_tap(elemen_by,cts,element_info, xy=[]):
# elements_by(elemen_by, cts, element_info).tap(x=xy[0], y=xy[1])

def send_keys(mOperate,cts):
elements_by(mOperate, cts).send_keys(mOperate["text"])


# 封装常用的标签
def elements_by(mOperate, cts):
elements = {

common.find_element_by_id : lambda :cts.find_element_by_id(mOperate["element_info"]),
common.find_elements_by_id : lambda :cts.find_elements_by_id(mOperate["element_info"]),
common.find_element_by_xpath: lambda :cts.find_element_by_xpath(mOperate["element_info"]),
common.find_element_by_name: lambda :cts.find_element_by_name(mOperate['name']),
common.find_elements_by_name: lambda :cts.find_elements_by_name(mOperate['name'])[mOperate['index']],
common.find_element_by_class_name: lambda :cts.find_element_by_class_name(mOperate['element_info']),
common.find_elements_by_class_name: lambda :cts.find_elements_by_class_name(mOperate['element_info'])[mOperate['index']]
}
return elements[mOperate["find_type"]]()

最后也贴下怎么监控men,cpu,fps

# 常用的性能监控
def top_cpu(pkg_name):
result = 0
cmd = "adb shell dumpsys cpuinfo | grep -w " + pkg_name+":"
temp = []
# cmd = "adb shell top -n %s -s cpu | grep %s$" %(str(times), pkg_name)
top_info = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.readlines()
for info in top_info:
temp.append(info.split()[2].decode()) # bytes转换为string
break
for i in temp:
if i != "0%":
print("cpu="+i)
result = int(i.split("%")[0])
return result

# 得到men的使用情况
def get_men(pkg_name):
result = "0"
cmd = "adb shell dumpsys meminfo %s" %(pkg_name)
temp = []
m = []
men_s = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.readlines()
for info in men_s:
temp.append(info.split())
m.append(temp)
for t in m:
result = t[19][1]
break
return int(result.decode())

# 得到fps
def get_fps(pkg_name):
_adb = "adb shell dumpsys gfxinfo %s | grep -A 128 'Execute' | grep -v '[a-Z]' "%pkg_name
result = os.popen(_adb).read().strip()
result = result.split('\r\n')
# r_result = [] # 总值
# t_result = [] # draw,Process,Execute分别的值
# f_sum = 0
for i in result:
l_result = i.split('\t')[-3:]
f_sum = 0
for j in l_result:
r = re.search(r"\d+\.\d+", str(j))
if r:
f_sum += float(r.group())
# t_result.append('%.2f'%f_sum)
return float('%.2f'%f_sum)

结束语

  • 由于篇幅原因,主要代码已经介绍完毕,基本上大方面的东西已经定了,现在只支持单机测试
  • 点击查看源码github
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 77 条回复 时间 点赞

好牛啊!收下了,感谢分享!已经fork!

不错的思路,封装的不错

—— 来自TesterHome官方 安卓客户端

思寒_seveniruby 将本帖设为了精华贴 29 Oct 00:07

加精理由:思路优秀有亮点 开源分享精神

#4楼 @seveniruby
您好,问一下,我加了好几次咱们的群,都没有审核通过,是群满了吗?我还能加入吗?谢谢

#5楼 @Pastel 那个群. 不注明身份一般不会让进

#6楼 @seveniruby 让备注论坛id,我已经写了的

8Floor has been deleted

好赞!请问楼周,配套环境是否有依赖?

为嘛报这个错?

#9楼 @jojotester 缺少什么,就用pip安装下

#10楼 @testAdminSuper 就是放到模块common.Goglobal里面的,看看引用情况

good job

alswl [Topic was deleted] 中提及了此贴 04 Nov 11:18

有个问题咨询一下testDAL.DBaseCaseList下self.BaseTestCase().to_primitive()不清楚什么作用,而且打印下来{'operate_type': None, 'index': None, 'time': None, 'text': None, 'element_info': None, 'msg': None, 'name': None, 'find_type': None}值都是空的

#16楼 @luna
看下schematics的官网资料

#17楼 @lose 请问这个是什么情况

D:\Python\Python35\python.exe D:/appiumn_auto-master/testRunner/runner4.py
Traceback (most recent call last):
File "D:/appiumn_auto-master/testRunner/runner4.py", line 10, in
from testRunner.runner import TestInterfaceCase,ga
File "D:\appiumn_auto-master\testRunner\runner.py", line 21, in
ga = Devices()
File "D:\appiumn_auto-master\testRunner\runner.py", line 20, in Devices
return BDevices.BgetDevices(mapp, PATH("../Devices.ini"))
File "D:\appiumn_auto-master\testBLL\BDevices.py", line 5, in BgetDevices
return DDevices.appDevices(MAppDevices, f)
File "D:\appiumn_auto-master\testDAL\DDevices.py", line 7, in appDevices
config.read(f)
File "D:\Python\Python35\lib\configparser.py", line 696, in read
self._read(fp, filename)
File "D:\Python\Python35\lib\configparser.py", line 1012, in _read
for lineno, line in enumerate(fp, start=1):
UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 298: illegal multibyte sequence

#18楼 @jojotester

  • 注意编码问题
  • 如果监控fps,请打开手机开发中选项-GPU呈现模式分析-打开这个在adb shell dumpsys。。
20Floor has been deleted

请问下,为什么设备在连接,但是一直提示设备不存在。
Remote=http://localhost:4723/wd/hub
appiumjs=node D:\Program Files (x86)\Appium\node_modules\appium\bin\appiumjs
[selenium]
selenium_jar = java -jar D:\app\appium_study\img\selenium-server-standalone-3.0.1.jar
sel_remote=http://127.0.0.1:4444/wd/hub
open_url=http://182.254.228.211:9000/index.php/Admin/index/login.html
这几个配置不太明白是什么作用,可以说下吗?

编码问题解决了~

请问作为示例的APP右上角的悬浮按钮怎么处理,影响了click

#23楼 @jojotester 你好 请问你是直接gitclone下来的内容,本地有修改什么运行的吗?

25Floor has been deleted

#17楼 @lose 那个函数作用理解啦,可是运行的时候我单个operate_type之类的能get到值,可是打印下来self.BaseTestCase().to_primitive()的值都是默认的none

#26楼 @luna 你可以理解为其实就是一个实体类,打印出来为空,说明实体类里面的值没有设置

#24楼 @sunshine424 改成你自己的appium和selenium路径即可

提点小建议,类,方法命名规则,看着,实在有些受不了

#29楼 @sentury
好的,谢谢建议,刚好这里我也想优化下,今天更新后,麻烦帮忙看下~

@lose 加一下QQ吧,有些地方看不明白,想请教你 157733192

#27楼 @lose 可以加一下qq嘛,我的qq是2427536642,我就是下载你的脚本运行的,搞不清为什么实体类里的值没设置,我调试下来类那边觉得都是对滴啊😓

#28楼 @jojotester [DEFAULT]
selenium_appium=appium
Remote=127.0.0.1
appiumjs=node D:\app\Appium\node_modules\appium\bin\appium.js
port=4723
[selenium]
sel_remote=http://127.0.0.1:4444/wd/hub
open_url=http://182.254.228.211:9000/index.php/Admin/index/login.html

主要是这两个我不太明白?需要换成什么路径呢?

#33楼 @sunshine424 D:\app\Appium\node_modules\appium\bin\appium.js 你的appium安装的路径;

#34楼 @jojotester [DEFAULT]
selenium_appium=appium
[appium]
devices=7N2MWW1447004962
Remote=127.0.0.1
appiumjs=node D:\Program Files (x86)\Appium\node_modules\appium\bin\appium.js
port=4723
[selenium]
selenium_jar = java -jar E:\studyui\appiumn_auto-master\img\selenium-server-standalone-3.0.1.jar
sel_remote=http://127.0.0.1:4444/wd/hub 【这里需要配置??】
open_url=http://182.254.228.211:9000/index.php/Admin/index/login.html【这里需要配置??】

设备id和appium,selenium都已经修改了 ,但是运行runner还是报错,找不到设备。。。

#35楼 @sunshine424 报错内容贴上来

File "E:\studyui\appiumn_auto-master\testRunner\runner.py", line 118
print(u"设备不存在")
^
SyntaxError: invalid syntax

#36楼 @jojotester File "E:\studyui\appiumn_auto-master\testRunner\runner.py", line 118
print(u"设备不存在")
^
SyntaxError: invalid syntax

#38楼 @sunshine424 没遇到这种情况。。。

#39楼 @jojotester 上面的配置文件修改的除了路径其他都和你一样吧?

#38楼 @sunshine424 你这是代码有问题,语法错误,检查下代码

#41楼 @lose 代码没有动过 直接下载下来 然后改了下设备的配置文件 其他没动过

测试小书童 [Topic was deleted] 中提及了此贴 14 Nov 12:49

所有的引用都报错,引用都是无效,不知道是否有人遇到?

#44楼 @sunshine424 我也遇到同样的问题,

>>> from common.variable import GetVariable as common
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "D:\software\pycharm\PyCharm 4.5.3\helpers\pydev\pydev_import_hook.py", line 21, in do_import
module = self._system_import(name, *args, **kwargs)
File "D:\software\pycharm\PyCharm 4.5.3\helpers\pydev\pydev_import_hook.py", line 21, in do_import
module = self._system_import(name, *args, **kwargs)
ImportError: No module named 'common'

#41楼 @lose 本身down下来的代码中,print代码里面多了一个u,已经解决。

#46楼 @sunshine424 那你本身更改了编码方式了>>Unicode

研究一下

@lose
楼主,请问你这个框架对iOS同样适用的吗?只需要换一下配置文件吗?

#49楼 @LIUTIANTIAN 没有适配ios,用例和监控信息需要做适配,这个可以到入口的时候去控制下,你可以自己去完成,我这边是先以android的功能为主,等安卓多设备并行搞定后,会尝试扩展ios

#50楼 @lose
楼主 我基本是小白 iOS取cpu fps 电量这些数据 是怎么取?和安卓思路一样么?

赞一个

赞~ 真希望这个是iOS的

一开始打开LZ的项目,什么都没打开,然后发现xml是空的,workspace.xml不知道什么原因无法识别,用记事本打开也不行

runner.py运行时提示找不到common

很赞!学到知识了

哎,缺少太多文件了,到处都是灰色找不到文件的报错,小白不懂用

#55楼 @xjdhj

  • 是Common大写的。。你引用错了,后面的as common是别名,之前的历史遗留原因,没有改名。。
  • 那里的xml是ide自带的
  • 灰色的意思是,没有使用到。。

测试报告是不是可以优化下呢,比如弄成HTML格式的

60Floor has been deleted

###能装的库装了,卡在这里,继续研究中……@lose,求助,谢谢
ImportError: No module named 'seleniumrequests'
[Finished in 0.5s with exit code 1]

#61楼 @a_little 那个库请下载源码后在安装,现在最新版本没有去用selenium,也可以先屏蔽

感谢,已经安装了selenium-requests,之前一直搜索的selenium requests没加-,边运行边根据报错修改了一下,模块没问题现在能跑起来了,报错在这里,继续学习中……

ps:模块引用是common改成Common,具体需改动的地方根据运行结果提示改动。
需要下载的第三方库:xlsxwriter;selenium-requqsts;pyyaml(import yaml这里安装的第三方库是pyyaml,装了半天yaml不行,原来要装pyyam,后面学习的同学可以注意下),我用的pip install命令安装

#59楼 @chancoder 用excel作为附件的方式比较好,这样扩展性比较强,我也是参照了几家云测平台的方式做的

66Floor has been deleted

@lose
您好,周末一直在看,卡在这里运行,跑不下去了,报错信息截图了,求指点,谢谢!能加一下qq或者微信(1013091229)

#67楼 @a_little get_apk_pkg获取包名的时候报错了,自己调试下,没有对其他型号手机进行过测试

调试了半天还是这个错误 result = output.split()[1].decode()[6:-1],这里的[6,-1]范围是根据什么定义的呢?
IndexError: list index out of range,百度了这个异常,是因为越界了,范围不对,那应该怎么确定范围呢


已经将common改为Common了,怎么还有报错呢?求问

#70楼 @aya 你的项目都没有配置python环境,看你截图上面的灰条提醒,配置好了再运行

72Floor has been deleted

研究了一阵子。。该装的库都装了,现在出现这个问题

为什么变量会出现未定义呢??

@jojotester 请问邮件那边是不是参数都需要自己重新设置,我这里报错了

请问这问题该怎么解决???

#75楼 @x234115233 缺少了模块,去安装下~
@hlfang 检查下你的路径,错误信息里面有了

@lose,新人求教,关于监控性能,fps这个,我用windows,输入adb shell dumpsys gfxinfo ‘包名’ | findstr -A 128 'Execute' | findstr -v '[a-Z]',没有结果,只能用 adb shell dumpsys gfxinfo ‘包名’。然后关于帧率的计算,看你的报告结果是100多,你这个数字的单位是什么。我在网上查说正常情况下帧率16ms,也就是60帧/秒

我在执行>adb shell dumpsys gfxinfo com.idelan.app.HYWifiSocket 返回如下数据

数据中并没有Execute,请问这是怎么为什么?

@lose 新手刚接触这块内容求指导,我在执行过程中碰到的,请问路径是需要重新配置吗,在哪里进行配置呢

#78楼 @hukui51770 @hlfang 打开手机开发者模式--GPU呈现模式分析--在adb shell dumpsys gfxiinfo中

#75楼 @x234115233 邮件需要配置好自己的秘钥,先看看官方文档

#69楼 @a_little 你这个问题,估计是不同的手机获取包名的时候不兼容,自己调试下,原理比较简单,就是用aapt dump badging 获取文件后,再截取字符串

#74楼 @debi999 异步调试代码我删除了,可以用同步的:

pool = Pool(len(devices_Pool))
pool.map(runnerCaseApp, devices_Pool)
pool.close()
pool.join()

张小强 回复

你好!遇到同样的越界问题了!请问解决了么?!怎么解决的?

作者你好,这个错误能否帮忙查看一下
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 1318, in do_open
encode_chunked=req.has_header('Transfer-encoding'))
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1239, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1285, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1234, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1026, in _send_output
self.send(msg)
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 964, in send
self.connect()
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 936, in connect
(self.host,self.port), self.timeout, self.source_address)
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 722, in create_connection
raise err
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 713, in create_connection
sock.connect(sa)
ConnectionRefusedError: [Errno 61] Connection refused

先关闭,准备开始优化下等优化好了再次分享,谢谢

测试小书童 关闭了讨论 25 Apr 19:09
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up