Appium APP UI自动化测试——API介绍

0. 定位前的准备工作

在定位APP控件时,需要将APP页面dump到uiautomatorviewer中,然后通过uiautomatorviewer定位控件

能够将手机界面dump出来的前提:

1.打开appium并处于监听状态

2.电脑已开启模拟器或连接真机

3.adb已连接(cmd中输入adb devices,会显示已有设备连接)
在这里插入图片描述

- uiautomatorviewer打开方式

双击sdk\tools下的uiautomatorviewer.bat文件,等待出现第二个窗口Appium APP UI自动化测试——API介绍_第1张图片

Appium APP UI自动化测试——API介绍_第2张图片
Appium APP UI自动化测试——API介绍_第3张图片

APP中的3种属性:text、resource-id、class,在APP中,id/class_name基本上都不是唯一的,xpath可以写成唯一的

1. 通过id定位

定位方式 说明
find_element_by_id 找到一个,如果当前界面有多个相同id的控件,则找到第一个
find_elements_by_id 找到一组,平行结构的ID可能是一样的,下标从0开始

Appium APP UI自动化测试——API介绍_第4张图片

ele1 = driver.find_element_by_id("cn.xiaochuankeji.tieba:id/title")
print(ele1.text)  #获取文本信息
ele1.click()  #点击
ele2 = driver.find_elements_by_id("cn.xiaochuankeji.tieba:id/title")   #找到一组,平行结构的ID可能是一样的
ele2[2].click()  #通过下标区分

2. 通过class定位

  • 通过class定位:在APP中,class代表控件类型,所有控件肯定都有class属性
  • 与web端class属性定位有区别,在app中,class属性更像web中标签的概念
  • android中大多数控件都放在android.widget下,
  • TextView:文本类型 输入框:Edit.Text 图标:ImageView
  • 安卓控件是根据从左到右,从上到下排布的,可根据数字来具体定位到某一控件
定位方式 说明
find_element_by_class_name 找到一个,如果当前界面有多个相同class的控件,则找到第一个
find_elements_by_class_name 找到一组,平行结构的class可能是一样的,下标从0开始
#当前界面只有一个相同的class属性控件,使用element
ele3 = driver.find_element_by_class_name("android.widget.TextView")

#当前界面有很多相同的class属性控件,使用elements
# 会把当前所有相同class的控件都找出来,再通过下标定位具体控件
ele4 = driver.find_elements_by_class_name("android.widget.TextView")  #ele4此时是一个列表,表中放了很多控件
#对于文本控件,可加下面的日志,查看对应下标
for i in range(0,len(ele4)):
    print("第"+str(i)+"个="+ele4[i].text)   #将每个控件的文本信息及其下标打印出来(i是整型,无法与字符串直接连接,故转换成字符串)
ele4[3].click()   #点击想要的控件
#对于图片控件,根据dom树来确定下标,将没展开的都展开,查看ImageView,下标是从0开始

3. 通过xpath定位

-使用xpath定位格式://class属性[@resource-id=‘id属性’]

  • APP一般使用xpath相对路径定位,不使用绝对路径,因为绝对路径会很长
通过xpath定位注意点
xpath通过id查找单个元素(定位关注按钮),使用element
xpath通过text文本定位,如果文本是动态的(比如发的朋友圈动态),尽量不要@text属性
xpath通过text文本定位,无控件属性时,可使用正则代替,如//[text=‘图文’]
xpath可通过class查找单个元素,class既能当一种控件类型,也能当一种属性
使用多个属性定位,使用and连接,如//*[@resource-id=‘cn.xiaochuankeji.tieba:id/title’ and @text=‘视频’]
通过层级定位:父级找子级,先定位到父级,父级后跟/,然后后面跟子级的控件类型,xpath下标从1开始
子级定位到父级,可使用…实现
使用xpath定位肯定想要路径是唯一的,所以尽量不要使用find_elements这种方法
#xpath通过id查找单个元素(定位关注按钮),使用element
ele5 = driver.find_element_by_xpath("//android.widget.TextView[@resource-id='cn.xiaochuankeji.tieba:id/title']")
ele5.click()
#xpath通过text文本定位
#注意:如果文本是动态的(比如发的朋友圈动态),尽量不要@text属性
ele7 = driver.find_element_by_xpath("//android.widget.TextView[@text='关注']")
ele7.click()
#xpath通过text文本定位,无控件属性
ele8 = driver.find_element_by_xpath("//*[text='图文']")
ele8.click()
#xpath通过class查找单个元素(定位发布话题中的edittext)
driver.find_element_by_xpath("//android.widget.EditText").click()
#class既能当一种控件类型,也能当一种属性
driver.find_element_by_xpath("//*[@class='android.widget.EditText']").click()
#组合定位(定位视频,定位搜索)
#使用多个属性定位,使用and连接
driver.find_element_by_xpath("//*[@resource-id='cn.xiaochuankeji.tieba:id/title' and @text='视频']").click()
#通过层级定位:父级找子级,搜索按钮
#先定位到父级,父级后跟/,然后后面跟子级的控件类型,xpath下标从1开始
driver.find_element_by_xpath("//android.widget.FrameLayout[@resource-id='cn.xiaochuankeji.tieba:id/search_b']/android.widget.ImageView[1]")
#定位兄弟级控件1:从子级定位父级(我的按钮),再从父级定位到兄弟级
#我->爸爸->我哥
driver.find_element_by_xpath("//*[@text='我的']/../android.widget.ImageView").click()
#定位兄弟级控件2:先找到父级的父级,然后找到父级的兄弟级的子级(最右按钮上的文案信息)
#我->爸爸->爷爷->大伯->大伯的儿子
driver.find_element_by_xpath("//*[@text='最右']/../../android.view.View[3]/android.widget.TextView").text

使用xpath定位肯定想要路径是唯一的,所以尽量不要使用find_elements这种方法

#xpath通过id查找多个元素(定位发布话题按钮),使用elements,列表下标从0开始
#使用xpath定位肯定想要路径是唯一的,所以尽量不要使用find_elements这种方法
ele6 = driver.find_elements_by_xpath("//android.widget.TextView[@resource-id='cn.xiaochuankeji.tieba:id/title']")
ele6[2].click()  #点击第3个

4. 操作类API

动作 代码实现
控件点击 .click()
文本输入 send_keys()
清空内容 .clear()
获取控件文本信息 .text
获取手机屏幕分辨率 get_window_size()

4.1 控件点击

#控件点击:.click()  适用于任何控件
ele = driver.find_element_by_id("cn.xiaochuankeji.tieba:id/ic_search_b")
ele.click()

4.2 文本输入与清空

#控件输入:send_keys()   适用于输入框(属性为EditText)
#清空内容:.clear()
a = driver.find_element_by_id("cn.xiaochuankeji.tieba:id/search_input")
a.send_keys('123')  #输入内容
a.clear()   #清空内容

4.3 获取文本信息

#获取控件文本信息:.text
ele = driver.find_element_by_id("cn.xiaochuankeji.tieba:id/ic_search_b")
print(ele.text)  #获取控件文本信息,经常在断言时使用,很重要!!!

4.4 获取手机屏幕分辨率

#获取手机屏幕分辨率:get_window_size(),返回的是一个字典类型
height = driver.get_window_size()['height']  #获取高,返回的是float类型
width = driver.get_window_size()['width']  #获取宽,返回的是float类型
print("此手机的分辨率是:"+str(height)+'*'+str(width))

5. 属性获取方法

动作 代码实现
获取当前界面activity信息 .current_activity
获取控件的属性值 get_attribute()
判断控件是否显示 is_displayed()
判断控件是否可用 is_enabled()

5.1 获取当前界面的activity信息

#获取当前界面activity信息
cur_activity = driver.current_activity
print(cur_activity)

5.2 获取控件的属性值

#获取控件的属性值:get_attribute
ele = driver.find_element_by_id("cn.xiaochuankeji.tieba:id/ic_search_b")
print(ele.get_attribute("className"))  #获取控件的属性值
print(ele.get_attribute("resourceId"))

5.3 判断控件是否显示/可用

ele = driver.find_element_by_id("cn.xiaochuankeji.tieba:id/ic_search_b")
print(ele.is_displayed())  #判断控件是否显示,返回布尔类型
print(ele.is_enabled())  #判断控件是否可用,返回布尔类型,可点击返回True,不可点击返回False

6. swipe方法-滑动/点击/长按

6.1 页面滑动的必须条件

#实现页面滑动:swipe
#要实现页面滑动,必须要数据加载出来才可以
driver.implicitly_wait(60)  #先等待60秒,直到当前界面的某个控件出现
driver.find_element_by_id("cn.xiaochuankeji.tieba:id/ic_search_b").is_displayed()
time.sleep(5)  #再休眠5秒(给加载数据提供时间)

6.2 上下左右滑动

#从上到下:y值变大
#x不变,y从小变大:下滑  x可以取屏幕分辨率宽的中间值,如720的屏幕,x可取360
#x不变,y从大变小:上滑
driver.swipe(500,1000,500,200,3000)  #上滑  
#500和1000分别是x/y的起始坐标,500和200是x/y的终止坐标,3000:持续时间3000毫秒
driver.swipe(500,200,500,1000,3000)  #下滑
#从左到右:x值变大
#y不变,x从大变小:左滑
#y不变,x从小变大:右滑
driver.swipe(400,500,200,500,3000)  #左滑
driver.swipe(200,500,400,500,3000)  #右滑

6.3 点击/长按

driver.swipe(500,200,500,200,100)  #点击:x和y不变,持续时间很短
driver.swipe(500,200,500,200,3000)  #长按:x和y不变,持续时间较长

6.4 按屏幕相对位置滑动

#直接乘以坐标所占屏幕的比例,可实现不论手机屏幕分辨率是多少,代码都可以使用
height = driver.get_window_size()['height']
width = driver.get_window_size()['width']
driver.swipe(width*0.555,height*0.855,width*0.555,height*0.14,3000)

6.5 扩展

(1)查看控件的布局范围:
在Ui Automator Viewer中dump一下界面,然后点击该控件,找到bounds,后面对应的就是控件布局范围,如[17,1083][703,1108] ,x的布局范围是17到703,y的布局范围是1083到1108
Appium APP UI自动化测试——API介绍_第5张图片

(2)坐标的相对位置获取:可在一个正在调试的手机上,如分辨率为1280*720,找到想要想要实现的坐标移动点,如(400,1095,400,180),x/屏宽,y/屏高,可以取比例获取坐标的相对位置,如计算方式:400/720=0.555 1095/1280=0.855 180/1280=0.14

7. TouchAction

使用TouchAction前需要先导入TouchAction类
from appium.webdriver.common.touch_action import TouchAction

7.1 tap

#点击控件
ele = driver.find_element_by_id("cn.xiaochuankeji.tieba:id/ic_search_b")
TouchAction(driver).tap(ele).perform()
#点击坐标
TouchAction(driver).tap(x=100,y=160).perform()
#也可以使用相对比例的坐标
height = driver.get_window_size()['height']
width = driver.get_window_size()['width']
TouchAction(driver).tap(x=width*0.2, y=height*0.5).perform()

7.2 press

#press某个点
TouchAction(driver).press(x=500, y=308).release().perform()  
#release:释放,按下去再释放-相当于点击
#长按某个点
TouchAction(driver).long_press(x=500, y=308,duration=5000).release().perform()  
#duration=5000:持续时间5秒
#长按某个控件
ele = driver.find_element_by_id("cn.xiaochuankeji.tieba:id/expand_content_view")
TouchAction(driver).long_press(ele).perform()

8. keyevent

安卓按键(Android keycode),可以到网上搜索每个按键对应的数值
https://blog.csdn.net/midux/article/details/80064054
常用按键:

  • 返回键-4
  • 菜单键-82
  • 搜索键-84(在某个搜索框输入内容后直接调用这个按键即可搜索)
  • 回车键-66
  • 退格键-67
  • 删除键-112
driver.keyevent(4)  #直接传入对应的键值,传入4代表返回上一层

9. 截图方法

#截图:get_screenshot_as_file('路径/图片名称.png')
driver.implicitly_wait(60)
el = driver.find_element_by_id("cn.xiaochuankeji.tieba:id/ic_search_b")
driver.get_screenshot_as_file("E:/newCourse/test.png")

10. 中文输入法操作

  • 在APP中直接send_keys一个中文是输入不进去的,需要在初始化时,desired_caps里面加2个参数,设置之后就可以send_keys(‘中文’)
  • appium输入法是没有键盘的,如果自动化测试做完之后要继续做功能测试,需要去设置里面手动切换输入法
desired_caps['unicodeKeyboard'] = 'True'  #给手机安装一个appium的输入法
desired_caps['resetKeyboard'] = 'True'  #重置键盘,使appium输入法为默认输入法

11. 重置APP

在做APP自动化时,需要让每条用例都没有相互依赖关系,最简单粗暴的方法就是每次跑完一条用例时,将APP卸载掉,跑下一条用例时,再重新安装。

desired_caps['fullReset'] = 'True'   #在初始化时添加这个参数后,每次跑完之后就会把APP卸载掉
desired_caps['app'] = 'E:/newCourse/zuiyou518.apk'  #每次开始时会先安装APP

扩展:

  • APP卸载后,会清除用户操作产生的数据,而用户新建的数据来源于后端,不会被清除。比如收藏时会产生一个收藏标志,登录后会有一个登录记录,会被清除。

  • 而用户自己新建的数据,如果是以用户区分:

  • 登录抖音后收藏了某条视频,然后将APP卸载后,下次安装时收藏数据仍然存在(因为这个数据是记录在用户下的),而登录状态在卸载时是会被清除的,下次安装后需要重新登录。

  • 如果新建了数据,又要使用这个数据,需要将这些放在一条用例中。

  • 如果不想重置APP也可以,需要每次都查看一下登录状态,确认已经登录成功。在“我的”页面检查是否登录成功,如果是未登录状态,就要调用登录方法

  • 是否重置APP需要视具体业务场景而定。 如果业务与本地数据清除没有太大关系,就可以不重置(使用noReset),如果数据依赖关系太强,则需要重置。
    强交互的场景是不做自动化的。强交互一般是后端出问题,与UI自动化没有多大关系

12. toast处理

对于toast(发送信息后提示发送成功的黑色弹窗),需要加automationName参数,因为appium1.6.3以上版本才支持toast处理,之前装的是Uiautomator一代,所以需要加Uiautomator2对toast进行处理

#在初始化时加automationName参数
desired_caps['automationName'] = 'Uiautomator2'

#需要导入的库
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

#在定位控件、输入内容并点击发送后会弹出toast,toast定位:
toast_loc = ("xpath",'//*[contains(@text,"评论发送成功")]')  #将要定位的控件通过元组罗列出来,再把元组传进去
ele = WebDriverWait(driver,20,0.1).until(EC.presence_of_element_located(toast_loc))
#最大等待时间20秒,每隔0.1秒检测1次,直到当前界面存在了评论发送成功弹窗
print(ele.text)  #打印控件属性

你可能感兴趣的:(APP,UI自动化,app,android,软件测试)