Appium python+appium 开源框架分享

测试小书童 · 2016年10月28日 · 最后由 测试小书童 回复于 2017年04月25日 · 17449 次阅读
本帖已被设为精华帖!

介绍

  • 参数化 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 将本帖设为了精华贴 10月29日 00:07

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

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

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

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

8楼 已删除

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

为嘛报这个错?

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

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

good job

alswl [该话题已被删除] 中提及了此贴 11月04日 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。。
70楼 已删除

请问下,为什么设备在连接,但是一直提示设备不存在。
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 下来的内容,本地有修改什么运行的吗?

25楼 已删除

#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 代码没有动过 直接下载下来 然后改了下设备的配置文件 其他没动过

测试小书童 [该话题已被删除] 中提及了此贴 11月14日 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 格式的

30楼 已删除

### 能装的库装了,卡在这里,继续研究中……@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 作为附件的方式比较好,这样扩展性比较强,我也是参照了几家云测平台的方式做的

24楼 已删除

@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 了,怎么还有报错呢?求问

匿名 #19 · 2016年11月29日

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

18楼 已删除

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

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

@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

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

测试小书童 关闭了讨论 04月25日 19:09
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册