• Pyhton3+AirTest+[004]+小程序UI自动化之常用的高级方法


     
    1. 元素定位

      1. 建议尽量使用 text 定位元素
    # 定位一个元素
    poco(text='选择门店')
    # 如果text匹配多个元素,获取多个元素
    ele_list=list(poco(text='选择门店').wait(5))
    # 模糊定位,支持正则
    poco(textMatches="'^门店.*$'")
    1. 如果不能使用text定位,常用局部定位
    # 子元素
    poco(name='com.tencent.mm:id/nb').child(text='选择门店')
    # 后代
    poco(name='com.tencent.mm:id/nb').offspring(text='选择门店')
    #
    poco(name='com.tencent.mm:id/nb').parent()
    # 所有子元素
    poco(name='com.tencent.mm:id/nb').children()
    # 兄弟元素
    poco(name='com.tencent.mm:id/nb').sibling(text='选择门店')
    # 同样resourceid的元素列表
    list(poco(name='com.tencent.mm:id/nb'))
    1. 元素定位

      1. 通过相对坐标,控制点击的具体位置。左上角 (0, 0),右下角 (1, 1),横坐标为 x,纵坐标为 y
    po = poco(text='main_node')
    # 点击节点的中心点位置, 默认点击中心位置
    po.focus('center').click()
    # 点击节点的靠近左上角位置
    po.focus([0.1, 0.1]).click()
    # 点击节点的右下角位置
    po.focus([1, 1]).click()
    1. 等待元素的出现或者消失
    实际写用例时,有一些扫描或缓冲场景,需要等待元素出现或消失,才能进行下一步操作
    # 当使用wait_for_appearance或wait_for_disappearance时,建议处理PocoTargetTimeout,并截图,以方便在报告中查看出错时的页面情况
    try:
    poco(name='com.tencent.mm:id/nb').wait_for_appearance(timeout=10)
    poco(name='com.tencent.mm:id/nb').wait_for_disappearance(timeout=10)
    except PocoTargetTimeout:
    snapshot(msg="元素出现或未出现")
    1. 滑动和拖动
    # 拖动
    poco('star').drag_to(poco('shell'))
    # 滑动
    poco('Scroll View').swipe([0, -0.1]) # 滑动指定坐标
    poco('Scroll View').swipe('up') # 向上滑动
    poco('Scroll View').swipe('down') # 向下滑动
     
    # 向量滑动
    x, y = poco('Scroll View').get_position()
    end = [x, y - 0.1]
    dir = [0, -0.1]
    poco.swipe([x, y], end) # 从A点滑动到B点
    poco.swipe([x, y], direction=dir) # 从点A向给定方向和长度进行滑动
    1. 获取元素信息
    poco(name='com.tencent.mm:id/nb').attr("checkable")
    poco(name='com.tencent.mm:id/nb').get_position()
    poco(name='com.tencent.mm:id/nb').get_text()
    1. 连续滑动与自定义滑动操作
    from airtest.core.api import *
    
     # 获取当前手机设备
    android = device() 
    # 手指按照顺序依次滑过3个坐标,可以用于九宫格解锁
    android.minitouch.swipe_along([(100, 100), (200, 200), (300, 300)])
    
    
    
    # 自定义操作
    # 实现两个手指同时点击的操作
    from airtest.core.android.minitouch import *
    
    multitouch_event = [
        DownEvent((100, 100), 0),  # 手指1按下(100, 100)
        DownEvent((200, 200), 1),  # 手指2按下(200, 200)
        SleepEvent(1),
        UpEvent(0), UpEvent(1)]  # 2个手指分别抬起
    
    device().minitouch.perform(multitouch_event)
    
    
    # 三只滑动操作
    from poco.utils.track import *
    
    tracks = [
        MotionTrack().start([0.5, 0,5]).move([0.5, 0.6]).hold(1).
        MotionTrack().start([0.5, 0,5]).move([0.5, 0.6]).hold(1).
        MotionTrack().start([0.5, 0,5]).move([0.5, 0.6]).hold(1)
    ]
    poco.apply_motion_tracks(tracks)
    
    # 手势操作
    # 点击ui1保持1秒,拖动到ui2并保持1秒,然后抬起
    ui1.start_gesture().hold(1).to(ui2).hold(1).up()
    1. 点击元素偏移位置
    # 点击, focus为偏移值,sleep_interval为点击后的间隔时间
    poco(text="选择门店").click(focus=(0.1, 0.1), sleep_interval=5)
    1. 隐性等待元素
    # 隐形等待元素出现,元素出现后,wait()方法结束
    poco(text="选择元素").wait(timeout=5)
    1. 长按操作
    # 长按操作
    poco(text="选择门店").long_click(duration=2.0)
    1. 两指挤压收缩操作
    # 在给定的范围和持续时间下,在UI上两指挤压收缩操作
    poco.pinch(direction='in', percent=0.6, duration=2.0, dead_zone=0.1)
    1. 根据UI滑动
    # 根据UI的给定高度或宽度,滑动距离的百分比
    # 从底部上滑5秒
    poco.scroll(direction='vertical', percent=1, duration=5)
    # 从顶部下滑5秒
    poco.scroll(direction='vertical', percent=-1, duration=5)
    1. 高级拓展

      1. 滚动查找元素 (poco_swipe_to),滚动查找元素,当找到元素后,滑动元素到页面中间
    # 滚动查找元素
    def poco_swipe_to(text=None, textMatches=None, poco=None):
        find_ele = False
        find_element = None
        if poco is None:
            raise Exception("poco is None")
        if text or textMatches:
            swipe_time = 0
            snapshot(msg="开始滚动查找目标元素")
            if text:
                find_element = poco(text=text)
            elif textMatches:
                find_element = poco(textMatches=textMatches)
            while True:
                snapshot(msg="找到目标元素结果: " + str(find_element.exists()))
                if find_element.exists():
                    # 将元素滚动到屏幕中间
                    position1 = find_element.get_position()
                    x, y = position1
                    if y < 0.5:
                        # 元素在上半页面,向下滑动到中间
                        poco.swipe([0.5, 0.5], [0.5, 0.5+(0.5-y)], duration=2.0)
                    else:
                        poco.swipe([0.5, 0.5], [0.5, 0.5-(y-0.5)], duration=2.0)
                    snapshot(msg="滑动元素到页面中间: " + str(text) + str(textMatches) )
                    find_ele = True
                    break
                elif swipe_time < 30:
                    poco.swipe([0.5, 0.8], [0.5, 0.4], duration=2.0)
                    # poco.swipe((50, 800), (50, 200), duration=500)
                    swipe_time = swipe_time + 1
                else:
                    break
        return find_ele
    1. 观察者函数 (watcher)
    • 说明:利用子进程对页面元素进行监控,发元素后,自动操作。
    • 适用场景:多用于不可预测的弹窗或元素
    • 用法:watcher(text=None, textMatches=None, timeout=10, poco=None)
    def loop_watcher(find_element, timeout):
        """
        循环查找函数:每隔一秒,循环查找元素是否存在. 如果元素存在,click操作
        :param find_element: 要查找元素,需要是poco对象
        :param timeout: 超时时间,单位:秒
        :return:
        """
        start_time = time.time()
        while True:
            # find_element.invalidate()
            if find_element.exists():
                find_element.click()
                print("观察者:发现元素")
                break
            elif (time.time() - start_time) < timeout:
                print("--------------------观察者:等待1秒")
                time.sleep(1)
            else:
                print("观察者:超时未发现")
                break
    
    def watcher(text=None, textMatches=None, timeout=10, poco=None):
        """
        观察者函数: 根据text或textMatches定位元素,用子进程的方式循环查找元素,直到超时或找到元素
        :param text: 元素的text
        :param textMatches: 元素的textMatches,正则表达式
        :param timeout: 超时时间
        :param poco: poco实例
        :return:
        """
        print("观察者:启动")
        # 目标元素
        find_element = None
        if poco is None:
            raise Exception("poco is None")
        if text or textMatches:
            if text:
                find_element = poco(text=text)
            elif textMatches:
                find_element = poco(textMatches=textMatches)
    
        # 定义子线程: 循环查找目标元素
        from multiprocessing import Process
        p = Process(target=loop_watcher, args=(find_element, timeout,))
        p.start()
    1. 等待任一元素出现wait_for_any()
    poco.wait_for_any(),等待到任一元素出现,返回UIObjectProxy。
    check_list = [poco(text="选择门店"), poco(text = '请输入门店/门店地址')]
    poco.wait_for_any(check_list, timeout=20)
    1. 等待所有元素出现
    poco.wait_for_all(),等待所有元素出现。
    check_list = [poco(text="选择门店"), poco(text = '请输入门店/门店地址')]
    poco.wait_for_all(check_list, timeout=20)
    1. 用 swipe_along() 画个圈圈
    swipe_along 接口可以 实现连续划过一系列坐标 ,因此我们可以使用这个接口实现一些连续滑动的操作,比如手机屏幕的 滑动解锁 等。
    from airtest.core.api import *
    from airtest.core.android.rotation import XYTransformer
     
    auto_setup(__file__)
     
    # 获取当前手机设备
    driver = device()
    # 手指按照顺序依次滑过多个坐标
    driver.swipe_along([[919, 418],[111, 564],[1014, 824],[711, 638],[915, 415]])
    1. 双指缩放操作
    # 获取当前手机设备
    driver = device()
    # 向内捏合
    driver.pinch(in_or_out='in', center=None, percent=0.5)
    sleep(1.0)
     
    # 向外捏合
    driver.pinch(in_or_out='out', center=None, percent=0.2)
    sleep(1.0)
     
    driver.pinch(in_or_out='out', center=None, percent=0.2)
    sleep(1.0)

       7.  其他操作

        7.1 所有UI相关的操作都默认以UI的 anchorPoint 为操作点,如果想自定义一个点那么可以使用 focus 方法。调用此方法将返回 新的 设置了默认 焦点 的UI,重复调用则以最后一次所调用的为准。focus 所使用的是局部坐标系,因此同样是UI包围盒的左上角为原点,x轴向右,y轴向下,并且包围盒长宽均为单位1。很显然中心点就是 [0.5, 0.5] 。下面的例子会展示一些常用的用法

    poco('元素定位').focus('center').click()  # click the center

        7.2 将 focus 和 drag_to 结合使用还能产生卷动(scroll)的效果,下面例子展示了如何将一个列表向上卷动半页

    item = poco(type='元素定位')
    item.focus([0.5, 0.8]).drag_to(item.focus([0.5, 0.2]))

        7.3 在给定时间内等待一个UI出现并返回这个UI,如果已经存在画面中了那就直接返回这个UI。 如果超时了还没有出现,同样也会返回,但是调用这个UI的操作时会报错。类似的操作还有wait_for_appearance

    poco('元素定位').wait(5).click()  # wait 5 seconds at most,click once the object appears
    poco('元素定位').wait(5).exists()  # wait 5 seconds at most,return Exists or Not Exists

        7.4 点击click

    poco.click([0.5, 0.5])  # click the center of screen
    poco.long_click([0.5, 0.5], duration=3)

        7.5 截屏幕并以base64编码返回。截图的格式(png, jpg, …)由对应的sdk实现决定,大多数情况下是png。详见 ScreenInterface.getScreen

    from base64 import b64decode
    # 注意:在poco的某些引擎实现中不支持快照。
    b64img, fmt = poco.snapshot(width=720)
    open('screen.{}'.format(fmt), 'wb').write(b64decode(b64img))

        7.6 最简单的操作就是点击(click),也可以长按(long click),按多久都行

    # coding=utf-8
    
    from poco.drivers.unity3d import UnityPoco
    
    poco = UnityPoco()
    
    poco('元素定位').click()
    poco('元素定位').click()
    poco('元素定位').long_click()
    poco('元素定位').long_click(duration=5)

       

        7.7 poco里的坐标的取值范围是相对于屏幕的,屏幕的宽和高都为单位1,因此也叫百分比坐标。当你需要和某个UI控件附近的UI控件交互或者要点击某个按钮的边缘而不是中间时,那可以用 局部定位 。

    总的来说,和UI控件交互最终都是和坐标交互,例如点击一个按钮实际上就是点击某个坐标。 局部定位 就可以基于某个UI的左上角进行偏移,然后可以实现点击到这个UI控件内的各个坐标甚至UI外面的其他坐标。

    import time
    from poco.drivers.unity3d import UnityPoco
    
    poco = UnityPoco()
    
    image = poco('元素定位').child(type='Image')
    image.focus('center').long_click()
    time.sleep(0.3)
    image.focus([0.1, 0.1]).long_click()
    time.sleep(0.3)
    image.focus([0.9, 0.9]).long_click()
    time.sleep(0.3)
    image.focus([0.5, 0.9]).long_click()
    time.sleep(0.3)

        7.8 选中的UI外单击。通过它的名字标签点击一些模型是非常有用的

    # coding=utf-8
    
    from poco.drivers.unity3d import UnityPoco
    
    poco = UnityPoco()
    
    item = poco(text='元素text').focus([0.5, -3])
    item.long_click()

        7.9 如何使用拖动来滚动列表

    # coding=utf-8
    
    import time
    from poco.drivers.unity3d import UnityPoco
    
    poco = UnityPoco()
    
    listView = poco('元素定位')
    listView.focus([0.5, 0.8]).drag_to(listView.focus([0.5, 0.2]))
    time.sleep(1)

        7.10 下面例子展示了怎么样在商城界面中购买当前屏幕的所有商品

    # coding=utf-8
    
    poco = Poco(...)
    
    bought_items = set()
    for item in poco('元素定位').child('元素定位').offspring('元素定位'):
     
        item_name = item.get_text()
    
        if item_name not in bought_items:
            item.click()
            bought_items.add(item_name)

        7.11 一些复杂的测试用例中,不可能只是不断地主动控制或者读取属性。通过被动地获取UI状态改变的事件,这样有助于写出不混乱的测试脚本。Poco提供了简单的轮询机制去同时轮询1个或多个UI控件,所谓轮询就是依次判断UI是否存在。

    下面例子展示的是最简单的UI同步

    # coding=utf-8
    
    from poco.drivers.unity3d import UnityPoco
    
    poco = UnityPoco()
    
    # start and waiting for switching scene
    start_btn = poco('元素定位')
    start_btn.click()
    start_btn.wait_for_disappearance()
    
    # waiting for the scene ready then click
    exit_btn = poco('元素定位')
    exit_btn.wait_for_appearance()
    exit_btn.click()

        7.12 下面例子展示轮询UI时等待 任意一个 UI出现就往下走

    # coding=utf-8
    
    from poco.drivers.unity3d import UnityPoco
    from poco.exceptions import PocoTargetTimeout
    
    poco = UnityPoco()
    
    bomb_count = 0
    while True:
        blue_fish = poco('元素定位').child('元素定位')
        yellow_fish = poco('fish_emitter').child('yellow')
        bomb = poco('元素定位').child('元素定位')
        fish = poco.wait_for_any([元素1, 元素2, 元素3])
        if fish is bomb:
            # 跳过炸弹,数到3退出
            bomb_count += 1
            if bomb_count > 3:
                return
        else:
            # 否则点击鱼收集。
            fish.click()
        time.sleep(2.5)

        7.13 下面例子展示轮询UI时等待 所有 UI出现才往下走

    # coding=utf-8
    
    import time
    from poco.drivers.unity3d import UnityPoco
    
    poco = UnityPoco()
    
    poco(text='元素定位').click()
    
    blue_fish = poco('元素定位').child('111')
    yellow_fish = poco('元素定位').child('111')
    shark = poco('fish_area').child('black')
    
    poco.wait_for_all([111, 222, 333])
    poco('444').click()
    time.sleep(2.5)

        7.14 介绍一种加快UI操作速度的一种方法(即冻结UI),只是对于复杂的选择和UI遍历有效,如果只是简单的按名字选择请不要用这种方法,因为一点效果都没有冻结UI其实就是将当前界面的层次结构包括所有UI的属性信息抓取并存到内存里,在跟UI交互时就直接从内存里读取UI属性,而不用在发送rpc请求到game/app里去操作UI。好处就是一次抓取(消耗几百毫秒),可以使用多次,读取UI属性几乎不消耗时间,同时坏处就是,你需要手动处理UI同步,如果抓取了层次结构后,某个UI控件位置发生了变化,此时如果仍然点击这个UI的话,就会点击到原来的位置上,而不是最新的位置,这很容易导致奇怪的测试结果

    下面两个例子分别展示使用了冻结UI和不使用冻结UI的效果区别

    import time
    from poco.drivers.unity3d import UnityPoco
    
    poco = UnityPoco()
    with poco.freeze() as frozen_poco:
        t0 = time.time()
        for item in frozen_poco('1111').offspring(type='2222'):
            print item.get_text()
        t1 = time.time()
        print t1 - t0  # 大约6 ~ 8秒

    不冻结

    import time
    from poco.drivers.unity3d import UnityPoco
    
    poco = UnityPoco()
    t0 = time.time()
    for item in poco('1111').offspring(type='2222'):
        print item.get_text()
    t1 = time.time()
    print t1 - t0  # 约50 ~ 60 s
    当有些人一出生就有的东西,我们要为之奋斗几十年才拥有。但有一样东西,你一辈子都不会有,那就是我们曾经一无所有。
  • 相关阅读:
    星云精准测试有力提升金融复杂系统的测试能效
    疫情之下,精准测试的智能可信模式正在成为中流砥柱
    星云测试插装编译流程与CI集成
    自动化测试与精准测试的无缝对接
    “静默式”精准测试,让企业零成本完成黑盒测试的升级对接
    精准测试与开源工具Jacoco的覆盖率能力大PK
    【星云测试】Devops微服务架构下具有代码级穿透能力的精准测试
    【星云测试】开发者测试-采用精准测试工具对Spring Boot应用进行测试
    分享我们团队管理的最佳实践——程序员的周报应如何填写
    [原创]基于VueJs的前后端分离框架搭建之完全攻略
  • 原文地址:https://www.cnblogs.com/chushujin/p/15075521.html
Copyright © 2020-2023  润新知