当前位置:   article > 正文

UIautomator2:APP自动化测试方法与小技巧记录(文末附实用APP测试脚本编写模板)_uiaotumator2

uiaotumator2

uiautomator2是一个python的用来自动化操作手机的库,可用于APP自动化测试。就笔者的使用体验,比appuim更稳定、易用。本文以大家最常用的APP:微信为例子,记录uiautomator2的常见用法,便于自己和读者查阅。如果你觉得本文有用,还请收藏支持一下。

为方便查阅,环境配置及安装放在最后。
有问题也欢迎联系我:hausahan@gmail.com,问题解决后我会将问题添加在常见问题中。


  • 文末附实用APP测试脚本编写模板

常见用法及技巧

连接设备

在终端输入:adb devices,可以获取连接了电脑的手机名称。
另外,使用

adb shell dumpsys window | grep mCurrentFocus # Linux
adb shell dumpsys window | findstr mCurrentFocus # Windows
  • 1
  • 2

可以获取当前屏幕显示的APP的包名。

使用如下代码连接到手机:

class Phone:
    def __init__(self, deviceName, appName):
        self.deviceName = deviceName
        self.appName = appName
        self.d = u2.connect_usb(deviceName)
  • 1
  • 2
  • 3
  • 4
  • 5

打开APP

使用包名打开

例如我们要打开微信,可以使用上面的命令获取微信的包名,是:com.tencent.mm,然后在代码中打开:

class Phone:
    def __init__(self, deviceName, appName):
        self.deviceName = deviceName
        self.appName = appName
        self.d = u2.connect_usb(deviceName)		# connect to mobile
        self.d.app_start(appName)		# open the app which the package name is [appName]

if __name__ == '__main__':
    # Config
    deviceID = '9a9abd39'  # mobil device name: adb devices
    appID = 'com.tencent.mm'  # app package name: adb shell dumpsys window | grep/findstr mCurrentFocus
    
    phone = Phone(deviceID, appID)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
回到主屏幕使用text打开

如图,我们可以使用定位text的功能,在安卓主屏幕打开app:
在这里插入图片描述到我们的代码中就是将原来的self.d.app_start(appName)改为self.d(text='工作专用').click()

介绍第两种方法是因为,有时候会出现使用包名不能打开APP的情况,比如APP有分身,那么两个app的包名就会是一样的,打开很不方便。或者偶尔会uiautomator2抽风打不开之类的情况,使用text打开一般会更方便。

元素定位

text

text定位是最简单最常用的,使用方法如下:
屏幕如下时,想要点击的元素又是实时生成没有固定的ID,就可以使用这样的代码来点击:
在这里插入图片描述

# coding:utf-8

import uiautomator2 as u2

class Phone:
    def __init__(self, deviceName, appName):
        self.deviceName = deviceName
        self.appName = appName
        self.d = u2.connect_usb(deviceName)  # connect to mobile
        self.d(text='工作专用').click()		# 点击打开微信分身

    def doTest(self):
        self.d(text='月亮').click()		# 点击想要打开的聊天框


if __name__ == '__main__':
    # Config
    deviceID = '9a9abd39'  # mobil device name: adb devices
    appID = 'com.tencent.mm'  # app package name: adb shell dumpsys window | grep/findstr mCurrentFocus

    phone = Phone(deviceID, appID)
    phone.doTest()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

当屏幕中有多个关键词时,使用直接使用.click()可能达不到我们想要的效果,可以对d(text='xxx')的结果使用索引,如下,修改doTest方法:
在这里插入图片描述

    def doTest(self):
        targetPerson = self.d(text='月亮')
        targetPerson[-1].click()
  • 1
  • 2
  • 3

此外,在测试使用这个脚本的时候可能会发现,打开一些应用时,有时候会有一些加载时间,包括有时候在应用内跳转也会有。如果没有加载好就执行了点击,会因为找不到元素而报错。在本文的小技巧一章中提供了一种解决方法,可以使用尽可能少的等待时间,保证测试脚本的可用性和稳定性。

id

使用xpath可以定位元素ID比较确定的情况,例如系统底部的返回键/HOME键,或者当屏幕中只有一个输入框等情况,使用方法如下:
在这里插入图片描述

self.d(resourceId="com.tencent.mm:id/b8k").click()
  • 1

有些元素的id很不明显甚至没有,比如微信的输入框,那么就可以用下面的坐标点击方法选中,然后再往里面写入数据。

xpath

在weditor中点击,xpath会出现在中间的表格中

self.d.xpath('//*[@resource-id="com.tencent.mm:id/b79"]/android.widget.RelativeLayout[3]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]').click()
  • 1
坐标

坐标定位可用于text不确定,元素的xpath随测试变化等各种不确定情况,或者前两者都定位不到元素的情况,使用方法如下:
(P.S. 在屏幕中位置不确定的话,可以先将待点击元素通过滑动到顶部/底部的方法固定到一个位置)
在这里插入图片描述

self.d.click(0.5,0.91)
  • 1

常见操作

触摸/点击
self.d.click()
# or
self.d(text='xxx').click()
# or
self.d.click(float, float)
  • 1
  • 2
  • 3
  • 4
  • 5
双击
self.d(xxx).double_click()
  • 1
长按
self.d(text='工作专用').long_click(duration=1)
  • 1
滑动
    def getSize(self):
        x = self.d.window_size()[0]
        y = self.d.window_size()[1]
        return x, y

    def swipeUp(self, t=0.05):
        l = self.getSize()
        x1 = int(l[0] * 0.5)  # x坐标
        y1 = int(l[1] * 0.75)  # 起始y坐标
        y2 = int(l[1] * 0.25)  # 终点y坐标
        self.d.swipe(x1, y1, x1, y2, t)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
输入
self.d.set_text('text')
self.d.send_keys('text')
  • 1
  • 2
获取文字
self.d('定位操作').get_text()
  • 1
拖拽元素
self.d('定位操作').drag_to(x, y, duration=0.5)		# 拖到某个坐标
d(text='定位操作').drag_to(text='定位操作2', duration=0.25)		# 拖到某个元素中心位置
  • 1
  • 2
等待ui对象的出现/消失
d(text="Settings").wait(timeout=3)
d(text="Settings").wait_gone(timeout=1)
  • 1
  • 2

小技巧

当点击元素后页面切换且等待加载的时间不确定时

可以使用如下方法,等待直到需要的页面加载完成。

    def wait(self, s):
        times = 0
        maxWaitTime = 10
        while not self.d(text=s).exists:
            time.sleep(1)
            times += 1
            if times > maxWaitTime:
                log('There might be something wrong, restarting now......')
                self.doTest()
        time.sleep(1)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

该方法功能是:等待。直到屏幕中出现了某关键词,然后等待1S后继续测试。当等待时间超过
maxWaitTime时,就log错误信息,然后重新执行测试方法。相关方法在文末的脚本中有。
例如,初次打开微信会有那个地球的加载页,就可以使用这一方法等待其加载完成:

class Phone:
    def __init__(self, deviceName, appName):
        self.deviceName = deviceName
        self.appName = appName
        self.d = u2.connect_usb(deviceName)  # connect to mobile
        self.d(text='工作专用').click()

    def doTest(self):
        self.wait('微信')
        targetPerson = self.d(text='月亮')
        targetPerson[-1].click()

    def wait(self, s):
        times = 0
        maxWaitTime = 10
        while not self.d(text=s).exists:
            time.sleep(1)
            times += 1
            if times > maxWaitTime:
                log('There might be something wrong, restarting now......')
                self.doTest()
        time.sleep(1)


if __name__ == '__main__':
    # Config
    deviceID = '9a9abd39'  # mobil device name: adb devices
    appID = 'com.tencent.mm'  # app package name: adb shell dumpsys window | grep/findstr mCurrentFocus

    phone = Phone(deviceID, appID)
    phone.doTest()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

为什么不使用uiaotumator提供的wait方法?因为笔者觉得自己的用着更顺手一些,方便自定义重新开始的位置等。

常见问题及报错

安装时报错

Read timed out

此错误是连接时长超时,可以尝试加长超时时间,在使用pip时加上如下参数:pip --default-timeout=1000 install -U --pre uiautomator2

环境安装

安装过程常见问题和报错请参考:常见问题及报错—>安装时报错
电脑中需要有:PythonAndroid SDK,若没有,请点击链接前往安装。(SDK的链接是Android Studio的,因为笔者觉得通过这一方式获取的SDK是最官方的,而且这里也可以安装最方便官方的模拟器)
另外Linux系统需要配置环境变量才能使adb可以工作,请参考常见问题。

环境准备好后,在终端/命令行操作:

pip3 install uiautomator2
pip3 install weditor==0.6.4
  • 1
  • 2

然后使用数据线连接手机,打开USB调试,或直接使用Android Studio的模拟器,在终端输入:
weditor或者python3 -m weditor
初次运行会在手机上安装ATX调试器。请及时在手机上允许安装。

输入上面的命令后,会弹出默认浏览器打开调试网页,点击页面中间的Dump Hierachy可以获取最新手机屏幕页面。

双击手机页面截图可以在右侧生成代码并执行操作。
这一调试器很好用,稍微摸索一下就可以满足一般使用,不再赘述。

在模拟器中安装微信:在官网下载对应位的APK安装包,然后在模拟器打开,或连接了手机的情况下,在终端使用:
adb install weixinxxxxxx.apk将其安装到模拟器/手机上。

# coding:utf-8
import threading

import uiautomator2 as u2
import time, datetime
from random import randint

import os

def log(s):
    print('[{}]: {}'.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), s))

class Phone:
    def __init__(self, deviceName, appName):
        self.deviceName = deviceName
        self.appName = appName
        self.d = u2.connect_usb(deviceName)  # connect to mobile

    def doTest(self):
        self.d.app_stop_all()
        self.d.app_start(self.appName)
        self.wait('微信')

    def wait(self, s):
        times = 0
        maxWaitTime = 10
        while not self.d(text=s).exists:
            time.sleep(1)
            times += 1
            if times > maxWaitTime:
                log('There might be something wrong, restarting now......')
                self.doTest()
        time.sleep(1)


if __name__ == '__main__':
    # Config
    deviceID = '9a9abd39'  # mobil device name: adb devices
    appID = 'com.tencent.mm'  # app package name: adb shell dumpsys window | grep/findstr mCurrentFocus

    phone = Phone(deviceID, appID)
    phone.doTest()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/457682
推荐阅读
  

闽ICP备14008679号