(一)移动测试概念
1、定义
测试手机程序
2、测试的方面
- 功能测试:查看功能是否正常
- 安装卸载测试
- 升级测试
- 兼容性测试
- Android系统版本
- 厂商二次开发版本
- 不同分辨率
- 不同网络
- 网络切换、中断测试
- 使用中来电话、短信
- 横竖屏切换
- 健壮性:耗电性、流量消耗、崩溃回复
(二)环境搭建
1.java sdk
安装
配置JAVA_HOME和PATH
2.Android SDK
- 解压
- 配置Android_HOME和PATH
3.虚拟机安装
使用夜神模拟器
也可以使用真机
a. 手机通过usb线连接到电脑
b. 在手机上打开文件传输(通知栏,手机正在充电)
c. 在电脑上会发现多了一个CD驱动器,里面时手机的驱动
d. 安装驱动,电脑的设备管理器中就可以看到型号了
e. 开启开发者模式:手机-设置-关于手机-版本号(多次点击)
f. 打开usb调试:手机-设置-开发者选项-usb调试(打开)
1、ADB
命令:重要 a. 服务(如果发现代码连不上手机了) adb kill-server adb start-server b. 查看设备 adb devices c. 进入手机终端 adb shell d. 获取信息获取手机android版本:
adb shell getprop ro.build.version.release
获取手机当前运行的程序和界面的名称:
adb shell dumpsys window windows | findstr mFocusedApp
绿色是当前运行的程序activity,红色是当前程序运行的activity所在的包。
e.其他 i. 文件传输 adb push 电脑上的文件 手机上的位置 adb pull 手机上的文件 电脑上的位置 ii. 软件安装卸载 adb install 电脑上的apk文件路径 安装路径 adb uninstall 应用的包名 iii. 获取其他信息 adb shell am start -w 包名/.启动名
(三)自动化测试案例
1、自动化测试工具
选取Appnium。支持语言多,支持的平台多。
环境搭建:
1.安装appnium的程序
2.在python中安装Appnium-Python-Client
需要打开ADB、模拟器、Appnium、Pycharm
如果是之间导入的一个自己在电脑中直接建立的文件夹,没有匹配对应的python环境。
2、入门案例代码
1.连接设备
#1.连接设备
#组装一个字典,注明平台,系统版本,名称
#从appnium导入webderiver
from appnium import webdriver
import time
#连接移动设备所必须的参数
desired_caps = {} # desired_capabilities 是字典,先定义一个空字典
#当前要测试的设备名称
desired_caps["deviceName"] = "172.0.0.1:62001"
#看系统
desired_caps["platformName"] = "Android"
#系统的版本
desired_caps["latformVersion"] = "7.1"
#要启动的app的名称(app的唯一标识:包名)
desired_caps["appPackage"] = "com.android.setting"
#要启动的app的界面
desired_caps["appActivity"] = ".Settings"
driver = webdriver.Remote("http://127.0.0.1:4444/wd/hub",
desired_capabilities=desired_caps)
time.sleep(1)
#这里进行所需要的操作
#关闭app 关闭后需要释放资源
driver.close_app()
driver.quit()
亦或者:
#1.连接设备
#组装一个字典,注明平台,系统版本,名称
#从appnium导入webderiver
from appnium import webdriver
import time
#连接移动设备所必须的参数
desired_caps = {
"deviceName": "172.0.0;1:62001",
"platformName": "Android",
"latformVersion": "7.1",
"appPackage": "com.android.setting",
"appActivity": ".Settings"
}
#看系统
#系统的版本
#要启动的app的名称(app的唯一标识:包名)
#要启动的app的界面
driver = webdriver.Remote("http://127.0.0.1:4444/wd/hub",
desired_capabilities=desired_caps)
time.sleep(1)
#g关闭app 关闭后需要释放资源
driver.close_app()
driver.quit()
ADB进入命令行:
首先进入python模式
再下指令pip list查看当前已经安装的包
workon查看当前的虚拟环境。
从Remote点击查看webdriver.py
Appnium端需要配置 的环境变量:
退出configuraations后:
端口号,与代码端口号要一致。host的ip地址也要一致
点击start:(运行代码前要start)
代码中的的信息如何查找:
1.deviceName:
desired_caps["deviceName"] = "172.0.0.1:62001"
2.看系统
desired_caps["platformName"] = "Android"
注意首字母大写
3.看系统版本
#系统的版本
desired_caps["latformVersion"] = "7.1"
模拟器中查看:
4.要启动的app名称
#要启动的app的名称(app的唯一标识:包名)
desired_caps["appPackage"] = "com.android.setting"
5.要启动的app界面
#要启动的app的界面
desired_caps["appActivity"] = ".Settings"
4和5使用命令在命令行中查看:
获取手机当前运行的程序和界面的名称:
adb shell dumpsys window windows | findetr mFocusedApp
3、测试原理
代码通过remote连接服务器(Appnium client),将信息传到server(appnium),需要解析,server通过adb命令传递指令给手机。
4、基础操作
基础API:
- driver
close_app() | 关闭打开的应用 |
quit() | 断开连接(后续不能发送指令了) |
install_app('apk在电脑的绝对路径') | 安装应用 |
remover_app('应用的包名') | 卸载应用 |
is_app_installed('应用的包名') | 判断应用是否安装 |
push_file(目标位置,base64编码的内容) | |
pull_file(来源位置) | 返回值是base64编码的内容 |
pase_source | 获取界面xml源码 |
find_element... | |
find_elements... | |
current_package | 获取当前操作的应用的包名 |
current_activity | 获取当前操作的界面名称 |
python代码中查看:
print(driver.pase_source)
安装:需要放在当前目录下,r是将特殊字符转换回原生字符串
driver.install_app(r"文件目录\文件包名")
卸载:需要先判断是否已经安装
if driver.is_app_install("程序包名(adb指令查看)"):
driver.remove_app("程序包名(adb指令查看)")
查看包名、界面名称:
print(driver.current_package)
print(driver.current_activity)
- element
text | 获取元素文本的内容 |
click() | 点击元素对应的位置 |
get_attribute(属性名称) | 获取属性值 |
location | 获取元素左上角的坐标(相对于屏幕的左上角) |
size | 获取元素的宽高(字典) |
el = driver.find_element_by_xpath("//*[@text='显示']")
print(el.size)
print(el.text)
print(el.get_attribute("text"))
print(el.location)
5、输入文本
对于有些元素,可以接受文本输入。
- send_keys(文本内容)
可以输入文字,但对中文,在连接设备的时候要加上配置。(现在默认是可以的输入中文,若是不可以则把以下两行内容进行配置)
desired_caps('unicodeKeyboard')= True #unicode设置(允许中文输入)
desired_caps['resetKeyboard'] = True #键盘设置(允许中文输入)
如果对于同一元素,多次调用此方法,会先一个一个删除掉原内容,再输入。
- clear()
清除文本框的内容。(最后一个不会自动删除,需要清楚一个)
eg:
driver.find_element_by_xpath("//*[@resource-id=
'com.android.setting:id/search']").click()
time.sleep(1)
driver.find_element_by_xpath("//*[@resoure-id=
'android:id/search_src_text']").send_keys('abd')
driver.find_element_by_xpath("//*[@resoure-id=
'android:id/search_src_text']").send_keys('123')
driver.find_element_by_xpath("//*[@resoure-id=
'android:id/search_src_text']").send_keys('张三')
time.sleep(2)
driver.find_element_by_xpath("//*[@resoure-id=
'android:id/search_src_text']").clear()
6、元素定位
与web自动化不一样,web元素是在html上,而移动端是在xml上,可通过print(driver.pase_source)指令查看到。定位元素使用xpath的方式.
通过以下这个bat运行一个截图工具,查看页面的元素。
进去之后,点击左上角UI字眼下面偏绿色的按钮进行截图。再通过滑动点击页面元素,可在右边查看到元素信息。
#从appnium导入webderiver
from appnium import webdriver
import time
#连接移动设备所必须的参数
desired_caps = {} # desired_capabilities 是字典,先定义一个空字典
#当前要测试的设备名称
desired_caps["deviceName"] = "172.0.0.1:62001"
#看系统
desired_caps["platformName"] = "Android"
#系统的版本
desired_caps["latformVersion"] = "7.1"
#要启动的app的名称(app的唯一标识:包名)
desired_caps["appPackage"] = "com.android.setting"
#要启动的app的界面
desired_caps["appActivity"] = ".Settings"
driver = webdriver.Remote("http://127.0.0.1:4444/wd/hub",desired_capabilities=desired_caps)
time.sleep(1)
print(driver.pase_source)
# //*[text()='显示'] 的意思是在整个页面下寻找任意的元素(*),限定条件text
#在安卓手机中,text并不是文本,而是属于标签的属性
driver.find_element_by_xpath("//*[text()='显示']").click()
#g关闭app 关闭后需要释放资源
driver.close_app()
driver.quit()
以上报错原因是:< /,即开始和结束标签是在一起的,在安卓手机中,text并不是文本,而是属于标签的属性。
在xml中
<a herf="www.baidu.com"你好</a你好就是a标签的text,herf指的就是a标签的属性
如果中间没有值,可以直接如下写:
<a herf="www.baidu.com
改成:
driver.find_element_by_xpath("//*[text()='显示']").click()
#改成:
driver.find_element_by_xpath("//*[@text()='显示']").click()
一般情况下,通过文本获取,少数情况下通过id。
(四)模拟手势
1、安卓内在机制
1. 对于目前不需要在屏幕中显示的内容,是不需要处理的,为了节省硬件资源; 2. 安卓使用了栈的方式管理界面; 3. 页面滑动有“惯性”机制,会根据按下、抬起的位置以及总的时间,滚动不一样的距离。
2、滚动
swipe(self,start_x:int,start_y:int,end_x:int,end_y:int,duration:int = 0)
注意:duration默认是600单位是毫秒
它会影响实际滚动的距离
还需注意:
click方法,实际上并不是点元素,而是点元素所在位置。在获取的时候有位置,但可以经过滑动,位置发生了变化,可能点不准。非常有可能在点击之前睡一会,等待滑动结束。
scroll(origin_el,destination_el,duration)
scroll直接传递元素作为参数即可,不需要手动获取位置
scroll底层实现:与swipe有一些区别,没有中间的采样点,只有起始、结束,但最终的效果和swipe是一样的。
eg:
预估位置:
driver.swip(start_x=270,start_y=640,end_x=270,end_y=320)
第二种方式:
size = driver.get_window_size()
prinnt(size)
width = size["width"]
height = size["height"]
driver.swipe(start_x=width/2,start_y=height/3*2,
end_x=width/2,end_y=height/3)
滚动:
el1=driver.find_element_by_xpath("//*[@text='通知']")
el2=driver.find_element_by_xpath("//*[@text='WLAN']")
driver.scoll(el1,el2)
关于坐标:
第二种方式的滑动print:
3、拖拽
在安卓中,拖拽=按下 等待一定时间 移动 松手
drag_and_drop(origin_el,destinatiion_el)
eg:
el1.driver.find_element_by_xpath("//*[@text='酷安']")
el2.driver.find_element_by_xpath("//*[@text='京东']")
driver.drag_and_drop(el1,el2)
time.sleep(2)
4、TouchAction
- 作用
构建相对比较复杂的、连续的触摸动作
- 用法
- 创建TouchAction对象,需要把driver作为参数传递
- 通过各种方法添加动作
- 执行操作perform()
- 方法
- 按下
press(self,el,x,y,pressure)
如果传递了el参数,x,y可以不传
如果el为none,就需要传递x,y
pressure是ios专用的
- 长按
long_press(self,el,x,y,duration=1000)
如果传递了el参数,x,y可以不传
如果el为none,就需要传递x,y
- 移动
move_to(self,el,x,y)
如果传递了el参数,x,y可以不传
如果el为none,就需要传递x,y
- 等待
wait(self,ms)
ms等待时间,单位毫秒,默认600ms
- 松手
release()
- 轻敲
tap(el,element,x,y,count=1)
tap和click的区别:click有延迟促发效果(为了校验是不是双击),通过tap(el,count=2)可以模拟双击。
实例:
#需要再导一个包,其他内容要包括基本内容
from appnium.webdriver.common.touch_action import TouchAction
el1.driver.find_element_by_xpath("//*[@text='通知']")
el2.driver.find_element_by_xpath("//*[@text='WLAN']")
#实例化TouchAction
action = TouchAction(driver)
#既可以使用坐标又可以使用元素
action.press(el1).wait(2000).release()
#分开写:
#在移动的过程中wait必不可少,wait(0)是默认600ms
action.press(el1).wait(2000).move_to(el2)
#x和y是绝对坐标
action.press(x=270,y=640).wait(500).move_to(x=270,y=370)
action.release()
#执行 模拟收拾的使用,TouchActio进行模拟手势的时候,一定要记得执行操作
action.perform()
time.sleep(3)
5、图形滑动案例
案例如下:
安全不显示在当前屏幕中,需要滑动到下面让其显示在屏幕前,才能查找到
el1=driver.find_element_be_xpath("//*[@text='声音']")
el2=driver.find_element_be_xpath("//*[@text='WLAN']")
action = TouchAction(driver)
action.press(el1).wait(500).move_to(el2)
action.releasse()
action.perform()
time.sleep(1)
driver.find_element_be_xpath("//*[@text='安全']").click()
time.sleep(1)
driver.find_element_be_xpath("//*[@text='屏幕锁定']").click()
time.sleep(1)
driver.find_element_be_xpath("//*[@text='图案']")
time.sleep(1)
#按下的位置 Z型
action.press(x=105,y=450).wait(200).move_to(x=270,y45)
.wait(200).move_to(x=435,y=450).wait(200).move_to(x=270,y=615)
.wait(200).move_to(x=105,y=780).wait(200).move_to(x=270,y=780)
.wait(200).move_to(x=435,y=780)
action.release()
action.perform()
6、基础操作
- device_time :获取手机时间
- get_window_size():获取屏幕大小
- network_connection :获取手机网络信息
- 飞行模式
- WiFi
- 移动数据 6=2+4
- set_network_connection(网络模式数字) :设置手机网络信息
- keyevent(按键数字) :点击按键
- set_screenshot_as_file/save_screenshot(图片路径) :截屏
- open_notification() :打开通知栏
eg:
print(driver.device_time)
print(driver.network_connection)
driver.get_screenshot_as_file("jietu.png")