day06
- 能独立搭建app测试相关环境
 - 能通过命令在电脑端操作android系统中的应用(adb命令)
 

day07
掌握appium基础操作api的使用(安装、卸载、…)
掌握appium高级api操作(拖拽、滑动、…)
掌握appium手机操作api(按键…)

 
day08
- 能使用api模拟手势的常用操作(轻敲、按下、抬起、长按、移动、等待)
 - 能使用api对手机系统进行设置(网络、通知栏、按键)
 
获取分辨率、手机截图、获取和设置网络、发
送键到设备、打开和关闭通知栏- 扩展(切换环境(原生到webvier)、如何获取弹窗消息)
 

 
一、能独立搭建app测试相关环境
自动化用,手工也可以用,查看日志
1. 工具说明
- 主流工具
使用:appinum支持安卓和ios

 - app自动化执行原理(
代码在电脑上执行,appium开启控制,手机自动执行)

 - app类型(技术)

 
2. 环境搭建
- 所需环境 
  
- jdk(为了使用android-sdk俩功能)
 - android-sdk(1、ADB调试
2、uiautomatorviewer查看元素) - appium
 - 模拟器

 
 
(1) Jdk安装
- 说明:为什么要安装jdk?
安卓应用或开发工具是使用java语言开发,必须使用jdk。 - 安装:参考安装部署文档

 
(2)android-sdk
- 说明:android开发工具包
 - 安装: 
  
- 1、解压到指定目录
 - 2、将目录添加到path中
 
 
1、新建环境变量:ANDROID_HOME=D:\Android\sdk      
(这里为安装目录)
2、添加path路径,在Path中添
加:%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools;
提示:tools有查看元素工具,我们必须使用;platform-tools是adb命令工具所在目录
 

(3)appium安装
- 说明:需要安装appium服务端程序和python中调用的api库
 - 服务端: 
  
- 作用:将脚本发送给手机
 - 安装:双击安装程序,appium-desktop-setup-1.8.0.exe ,一直到完成即可。
 
 - python的appium. api库 
  
- 作用:自动化测试使用api
 - 安装:
pip install Appium-Python-Client==1.2.0 
 
(4)模拟器(使用mumu模拟器)
- 说明:安卓手机
 - 安装:雷电、mumu、夜神,默认安装完成即可

 
mumu模拟器连接:
- 找到mumu模拟器的安装路径,进入目录\emulator\nemu\vmonitor
 - cmd回车
 - adb connect 127.0.0.1:7555
 - 查看 adb devices
 
不使用雷电是因为,旁边字太小,一些软件打不开
3、 adb调试工具
- 说明:通过电脑,操作android系统的工具(命令)。
 
adb devices 查看是否连接上
(1)adb工作原理

(2)adb命令
1. 获取包名和启动名
- 包名:
一个安卓应用的唯一标识符,操作那个应用需要依赖包名 - 启动名:
应用中界面标识符,允许重复。 
1、mac/linux: adb shell dumpsys window | grep usedApp
2、windows: adb shell dumpsys window | findstr usedApp
 

 
2. 上传和下载命令
- 上传:adb push 路径\xxx.txt /sdcard
手机里面存储的所有东西都在sdcard文件夹里面 - 下载:adb pull /sdcard/xxx.txt 本地文件夹路径

 
3. 启动时间命令
命令:adb shell am start -W 包名/启动名
 
注意:查看时间 一般要冷启动(应用程序没有启动)
冷启动:应用程序未启动
热启动:应用程序已启动在后台或当前页面。
 

4. 查看日志(测试app手工必用)
- 命令:adb logcat > d:\xxx.log
 - 提示:对app操作时,要开启日志,记录app操作的步骤和异常。
比如忽然白屏 或 闪退怎么办,查看日志
使用重定向,复制电脑本地路径到重定向后面。不使用手机里面的地址,再拉出来费劲

 
5. 其他常用命令

提示:
1、adb start-server正常不需要手动启动,自动启动adb.exe进程。
当应用进程死机,需要执行杀服务,杀完后需要执行命令启动。
2、adb connect ip:端口 正常不要手动连接,系统会自动连接。如果执行adb devices没有看到设备列表,需要手动 连接
 
4、 uiautomatorviewer工具 查看元素定位信息 (相当于F12,不需要安装)
- 为什么要查看元素信息?
说明:自动化测试就是查找元素操作元素,要查找元素,就需要根据元素的信息来查找(id、class、text、…) - 如何查找?
 
使用:android SDK 自带工具:uiautomatorviewer工具
 
- 如何使用?
1、启动:(复制uiautomatorviewer,粘贴,回车)
或者配置使用ui回车,配置方法如下

 
2、截屏查看
 
配置ui技巧
太长记不住技巧:
1、复制并改名为ui,
2、cmd输入ui,即可打开
注意:不建议在源路径上改,时间长会找不着

 
 
使用常见问题

二、基础操作API
目标:能灵活运用Appium-基础api实现对于app应用的模拟测试过程脚本编写(基于unittest单元测试框架)
1、 入门示例
前置:必须启动appium服务、模拟器。
from appium import webdriver
# 定义字典变量
desired_caps = {}
# 字典追加启动参数
desired_caps["platformName"] = "Android"
 # 注意:版本号必须正确
desired_caps["platformVersion"] = "7.1.1"
 # android不检测内容,但是不能为空
desired_caps["deviceName"] = "192.168.56.101:5555"
desired_caps["appPackage"] = "com.android.settings"
desired_caps["appActivity"] = ".Settings"
# 设置中文
desired_caps["unicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
# 获取driver
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
 
2、 基础api
(1)启动应用(应用跳转)
- 方法:driver.start_activity(包名,启动名)
 - 说明:appium支持夸应用,可以在操作应用中切换到B应用。
 
(2)获取当前包名、启动名
- 方法
当前应用包名:driver.current_package
当前应用启动名:driver.current_activity - 练习
 
from time import sleep
from appium import webdriver
# 定义字典变量
desired_caps = {}
# 字典追加启动参数
desired_caps["platformName"] = "Android"
desired_caps["platformVersion"] = "7.1.1"
desired_caps["deviceName"] = "192.168.56.101:5555"
desired_caps["appPackage"] = "com.android.settings"
desired_caps["appActivity"] = ".Settings"
# 设置中文
desired_caps["unicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
# 获取drive
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
"""
    需求:
        1、启动设置后,暂停3秒,打开短信应用
        2、打印当前默认应用包名启动名
"""
sleep(3)
#  启动短信
driver.start_activity("com.android.messaging",".ui.conversationlist.ConversationListActivity")
# 打印包名和启动名
print("当前所在应用包名:",driver.current_package)
print("当前所在应用启动名:",driver.current_activity)
driver.quit()
 
(3)其他基础Api练习(关闭app和驱动对象、安装卸载和判断是否安装、置于后台)

 
 
 from time import sleep
from appium import webdriver
# 定义字典变量
desired_caps = {}
# 字典追加启动参数
desired_caps["platformName"] = "Android"
desired_caps["platformVersion"] = "7.1.1"
desired_caps["deviceName"] = "192.168.56.101:5555"
desired_caps["appPackage"] = "com.android.settings"
desired_caps["appActivity"] = ".Settings"
# 设置中文
desired_caps["unicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
# 获取driver
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
"""
    需求:
        1、判断百年奥莱是否安装,如果安装进行卸载,否则安装
        2、启动设置界面
        3、置于后台3秒钟
        4、关闭设置界面
        5、关闭app驱动
"""
# 判断百年奥莱是否安装
if driver.is_app_installed("com.yunmall.lc"):
    print("百年奥莱app已存在正在卸载...")
    # 卸载
    driver.remove_app("com.yunmall.lc")
    print("卸载百年奥莱app成功!")
else:
    print("百年奥莱不存在,正在安装...")
    # 安装
    driver.install_app("/Users/lgy/PycharmProjects/lgy/bj37-web01/day07-appium01//bainianaolaitemai_115.apk")
    print("安装百年奥莱app成功!")
sleep(3)
# 启动设置界面
print("启动设置界面...")
driver.start_activity("com.android.settings",".Settings")
sleep(3)
print("设置应用置于后台3秒钟...")
# 置于后台3秒
driver.background_app(3)
print("关闭设置app...")
# 关闭设置
driver.close_app()
print("获取关闭后的app报名")
print("关闭设置app,后获取包名:",driver.current_package)
sleep(3)
print("退出driver驱动")
driver.quit()
 
3、元素定位
(1)单个元素定位

 常用前面3个
- 需求

 
print("使用id点击放大镜...")
# 使用id -> 点击放大镜
driver.find_element_by_id("com.android.settings:id/search").click()
sleep(1)
print("使用class输入搜索hello...")
# 使用class 输入hell
driver.find_element_by_class_name("android.widget.EditText").send_keys("hello")
sleep(1)
print("使用xpath点击返回...")
# 点击返回 xpath
driver.find_element_by_xpath("//*[@class='android.widget.ImageButton']").click()
sleep(1)
print("使用name点击搜索...")
# 使用name定位
driver.find_element_by_accessibility_id("搜索设置").click()
sleep(3)
driver.quit()
 
(2)定位一组元素

需求
 
 移动端里面id可以重复。有值有很多,无值不会报错。
# 1、获取所有id为:android:id/title
els = driver.find_elements_by_id("android:id/title")
for el in els:
    print("元素id为com.android.settings:id/title的为本内容有:",el.text)
els = driver.find_elements_by_class_name("android.widget.TextView")
for el in els:
    print("元素class为android.widget.TextView的为本内容有:",el.text)
els = driver.find_elements_by_xpath("//*[contains(@text,'设')]")
for el in els:
    print("文本包含'设'内容有:",el.text)
sleep(3)
driver.quit()
 
4、元素操作
(1)点击、输入、清空
- 方法
 
 1、点击:元素.click()
 2、输入:元素.send_keys()
 3、清空:元素.clear()
 

- 需求

 
# 设置中文
desired_caps["unicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
# 1、点击放大镜
driver.find_element_by_xpath("//*[@resource-id='com.android.settings:id/search']").click()
# 2、输入hello
el = driver.find_element_by_xpath("//*[@resource-id='android:id/search_src_text']")
el.send_keys("hello")
# 3、2s 清空内容
sleep(2)
el.clear()
# 4、5s 输入你好
sleep(2)
el.send_keys("你好")
sleep(3)
driver.quit()
 
(2)获取元素信息 (断言使用)
- 方法
 
获取文本:元素.text
获取大小:元素.size
获取位置:元素.location
 
- 需求
1、打开设置app
2、点击放大镜
3、获取搜索文本值
4、计算搜索框中心触摸点(计算坐标:中心区域长为 位置+大小的一半) 
# 点击放大镜
driver.find_element_by_id("com.android.settings:id/search").click()
# 获取 菜单我的文本
text = driver.find_element_by_xpath("//*[@resource-id='android:id/search_src_text']").text
print("我的菜单,文本值为:",text)
# 获取 位置
location = driver.find_element_by_xpath("//*[@resource-id='android:id/search_src_text']").location
print("位置:",location)
# 获取 大小
size = driver.find_element_by_xpath("//*[@resource-id='android:id/search_src_text']").size
print("大小为:",size)
x= location.get("x")+ (size.get("width")/2)
y = location.get("y")+ (size.get("height")/2)
print("触摸中心位置x:{} y:{}".format(x,y))
 
(3)获取元素属性 (获取属性值信息)
- 方法:
 
元素.get_attribute("属性名")
 
- 注意:
因为不仅支持Android,也支持ios,属性值名称不对应

 - 需求:

 
# 点击放大镜
els = driver.find_elements_by_id("com.android.settings:id/title")
for el in els:
    print("--"* 50)
    print("1、enabled属性值为:",el.get_attribute("enabled"))
    print("2、text属性值为:",el.get_attribute("text"))
    print("3、content-desc属性值为:",el.get_attribute("name"))
    print("4、resource-id属性值为:",el.get_attribute("resourceId"))
    print("5、class属性值为:",el.get_attribute("className"))
    print("--"* 50)
 
5、滑动(常见)和拖拽
(1)swipe(start_x,start_y,end_x,end_y)
- 特点:精准滑动(基于两个坐标 点滑动)
 - 说明:针对坐标点进行操作
 
无法从上往下滑动。
练习示例:
driver.swipe(100,1000,100,400,duration=2000)
 
(2) scroll
- 特点:滚动(有惯性存在,滚动下不按下第⼀个元素)
 - 说明:针对两个元素进行操作
 
(3)drag_and_drop【推荐】
- 特点:拖拽(没有惯性,按下开始元素拖拽到指定元素位置)
 - 说明:针对两个元素进行精准操作
 



三、高级手势操作API(超过俩元素)

说明:
1、appium中封装了手势的操作方法,都在TouchAction类中,需要导包
2、所有的手势操作,最终都需要调用perform()方法才能执行
 
- 为什么要使用手势的操作?
 
-- 红包雨、九宫格解决,都需使用手动操作,之前学习的api最多是支持2个元素之间或2个坐标点之间操作。
 
1、轻敲
- api:TouchAction(driver).tap(el,x,y).perform()
 - 示例
 
from appium.webdriver.common.touch_action import TouchAction
wlan = driver.find_element_by_xpath("//*[@text='WLAN']")
TouchAction(driver).tap(wlan).perform()
 

2、按下与释放
- 按下:press(el,x,y)
 - 释放:release()
 - 示例
 
# 获取WLAN元素
wlan = driver.find_element_by_xpath("//*[@text='WLAN']")
loc = wlan.location
print(loc)
# 效果类似点击
TouchAction(driver).press(x=loc.get("x"),y=loc.get("y")).release().perform()
 

3、长按
- 方法:long_press(el,x,y)
 - 场景:在移动应用中,有时候需要长按才能激活菜单选项
 - 示例:
 
 # 获取WLAN元素
wlan = driver.find_element_by_xpath("//*[@text='WLAN']")
wlan.click()
# 必须暂时⼀定时间 暂停3秒(原因:元素未加载出来,直接长按坐标没有任何效果)
sleep(3)
# 效果类似点击
TouchAction(driver).long_press(x=777,y=375).perform()
 

4、移动及等待
- 移动:move_to(el,x,y)
 - 等待:wait(),
不等待没效果 - 案例:九宫格解锁
 
from time import sleep
from appium import webdriver
# 定义字典变量
from appium.webdriver.common.touch_action import TouchAction
desired_caps = {}
# 字典追加启动参数
desired_caps["platformName"] = "Android"
desired_caps["platformVersion"] = "6.0.1"
desired_caps["deviceName"] = "192.168.56.101:5555"
desired_caps["appPackage"] = "com.android.settings"
desired_caps["appActivity"] = ".Settings"
# 设置中文
desired_caps["unicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
# 获取driver
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
driver.implicitly_wait(10)
"""
    需求:绘制解锁图案 Z
    绘制坐标点:
        1、1048,340  1377,340  1707,340
        2、1377,669
        3、1048,999  1377,999  1707,999
"""
# 1、定位WLAN
WLAN = driver.find_element_by_xpath("//*[@text='WLAN']")
# 2、定位应用
app = driver.find_element_by_xpath("//*[@text='应用']")
driver.drag_and_drop(app,WLAN)
# 3、点击安全
driver.find_element_by_xpath("//*[@text='安全']").click()
# 4、点击屏幕锁定方式
driver.find_element_by_xpath("//*[@text='屏幕锁定方式']").click()
# 5、点击图案
driver.find_element_by_xpath("//*[@text='图案']").click()
# 必须暂停,登录绘制页面加载完成
sleep(2)
# 6、绘制
TouchAction(driver).press(x=1048,y=340).wait(100).move_to(x=1377,y=340).wait(100).move_to(x=1707,y=340).wait(100)\
    .move_to(x=1377,y=669).wait(100).move_to(x=1048,y=999).wait(100).move_to(x=1377,y=999).wait(100).move_to(x=1707,y=999).wait(100)\
    .perform()
sleep(3)
driver.quit()
 

四、手机操作API(安卓系统)
- 说明:使用appium框架的api操作android
 
1、常用api
- 查看当前网络类型
 - 设置网络类型(
要有权限) - 查看当前分辨率
 - 截图
 - 扩展网络类型

 
# 1、查看当前网络类型
print("当前网络类型为:",driver.network_connection)
# 2、设置网络类型为飞行模式
driver.set_network_connection(6)
print("设置之后的网络类型为:",driver.network_connection)
# 3、获取当前屏幕分辨率
print("当前屏幕分辨率为:",driver.get_window_size())
# 4、截图保存
driver.get_screenshot_as_file("./screen.png")
 

 
 
2、按键操作

"""
    需求:
       1、点击三次音量+  24
       2、点击返回       4
       3、点击两次音量-  25
"""
i = 0
# 三次增大音量
while i < 3:
    driver.press_keycode(24)
    i += 1
sleep(2)
# 点击返回
driver.press_keycode(4)
i = 0
# 两次减小音量
while i < 2:
    driver.press_keycode(25)
    i += 1
 # 提示:部分模拟器没有按键操作效果
 
3、通知栏
应用场景:检查服务器发送的通知
"""
    需求:
       1、打开通知栏,点击通知栏的信息
"""
# 打开通知栏
driver.open_notifications()
sleep(2)
# 查找信息并点击
driver.find_element_by_xpath("//*[@text='应用宝.apk']").click()
 

五、扩展
1、获取toast消息
- 说明:toast消息为移动应用中,⼀种黑底白字提示信息,有时间限制。
 - 为什么要获取toast消息?
断言内容 - 如何获取?
 
步骤
1、安装依赖库
2、配置driver启用参数
3、编写代码获取文本值
 
- 安装依赖库:pip install uiautomator2
 - 配置driver启用参数
 
 desired_caps['automationName'] = 'Uiautomator2'
 
- 编写代码获取文本值
 
 # 获取toast消息
msg = driver.find_element_by_xpath("//*[contains(@text,'请先勾选同意')]").text
print("toast消息为:",msg)
 

 
2、 切换webview【了解】 UI自动化测试
- 为什么要切换?
app中嵌套web信息,如果不切换无法定位操作 - 如何切换?
 
 1、获取当前环境   --> driver.contexts
 2、调用切换方法   --> driver.switch_to.context("环境")
 
- 示例
 
# 获取当前所有的环境
print(driver.contexts)
# 切换环境
driver.switch_to.context("WEBVIEW_com.android.browser")
 
(2) monkey 性能测试
- 什么是money?
android系统自带一种测试压力的小工具,主要测试系统或应用稳定性。 - monkey测试什么?
测试是否崩溃、闪退、死机。 - 执行命令?
 
 adb shell monkey -p com.yunmall.lc -v -v 10000 >xxx.log
 
-  
-p:包名
 -  
-v -v:日志
 -  
10000:乱抓的时间次数-s:设置随机种子数(两次执行随机种子数⼀样,执行的事件也是⼀样)
 -  
其他参数

 -  
日志查看什么?
 
搜索:“ANR”、ERROR、null、相关错误
 

 
 
 



















