第七单元 APP移动端测试高级

一、Appium介绍

Appium是一个移动端的自动化框架,可用于测试原生应用、移动网页应用和混合型应用,且是跨平台的。可用于IOS和Android以及firefox的操作系统。

原生的应用是指用android或ios的sdk编写的应用;移动网页应用是指网页应用,类似于ios中safari应用或者Chrome应用或者类浏览器的应用;混合应用是指一种包裹webview的应用,原生应用于网页内容交互性的应用。

重要的是Appium是跨平台的,何为跨平台,意思就是可以针对不同的平台用一套api来编写测试用例。

二、环境搭建

主要几个点如下:


image.png

1. appium安装

直接解压即可,打开Appium.exe


image.png

启动成功展示如下:


image.png

2. Appium库安装

# 安装
pip install Appium-Python-Client
# 检验是否成功
pip list

三、Appium使用

1. 打开模拟器或真机的应用

①打开手机应用
②打开Appium
③创建一个python项目,并创建一个文件
④将下面代码复制到文件中
⑤获取当前应用包名和启动activity并修改文件

from appium import webdriver
# server 启动参数
desired_caps = dict()
# 设备信息
# 平台信息,不区分大小写
desired_caps['platformName'] = 'Android'
# 系统版本,7.1.2可以写[7 ,7.1 , 7.1.2]
desired_caps['platformVersion'] = '7.1.2'
# 设备名称,可以随便写,但是不能乱写,Android可以随便写,但是ios必须正确的写
desired_caps['deviceName'] = 'emulator-5554'
# app的信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'
# 声明我们的driver对象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
driver.quit()

2. 脚本内启动其他app

driver.start_activity(appPackage,appActivity)

3. 关闭app

driver.terminate_app(包名)  # 关闭对应包名的app,不会关闭驱动对象

4. 关闭驱动对象

driver.quit()   # 关闭驱动对象,同时关闭所有关联的app

三、App基础操作API

完成app自动化需要一些基础条件的支持,本节将讲解APP初始化API。

3.1前置代码

# server 启动参数

desired_caps = {}
desired_caps['platformName'] = 'Android' 
desired_caps['platformVersion'] = '5.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)

3.2 安装APK到手机

driver.install_app(app_path) 
driver.install_app('C:\\Users\\Lenovo\\Desktop\\a.apk')

参数:app_path:脚本机器中APK文件路径

3.3 手机中移除APP

driver.remove_app(app_id) 

参数:app_id:需要卸载的app包名

3.4 判断APP是否已安装

driver.is_app_installed(bundle_id) 

参数:bundle_id: 可以传入app包名,返回结果为True(已安装) / False(未安装)
3.5 发送文件到手机

import base64
data = str(base64.b64encode(data.encode('utf-8')),'utf-8')
driver.push_file(path,data)
参数:

path:手机设备上的路径(例如:/sdcard/a.txt)
data:文件内数据,要求base64编码
Python3.x中字符都为unicode编码,而b64encode函数的参数为byte类型,需要先转码;
生成的数据为byte类型,需要将byte转换回去。

3.6 从手机中拉取文件

import base64
data = driver.pull_file(path) # 返回数据为base64编码
print(str(base64.b64decode(data),'utf-8')) # base64解码

参数: path: 手机设备上的路径

3.7获取当前屏幕内元素结构

driver.page_source  

作用:返回当前页面的文档结构,判断特定的元素是否存在

四、手机控件查看工具uiautomatorviewer

4.1 工具简介

用来扫描和分析Android应用程序的UI控件的工具.

4.1 如何使用

  1. 进入SDK目录下的tools目录,打开uiautomatorviewer
  2. 电脑连接真机或打开android模拟器
  3. 启动待测试app
  4. 点击uiautomatorviewer的左上角Device Screenshot,会生成app当前页面的UI控件截图


    image.png
  5. 选择截图上需要查看的控件,即可浏览该控件的id,class,text,坐标等信息


    image.png

五、APP元素定位操作

手工测试主要通过可见按钮操作,而自动化是通过元素进行交互操作。
元素的基本定位基于当前屏幕范围内展示的可见元素。

5.1 Appium常用元素定位方式

name value
id id属性值
class class属性值
xpath xpath表达式

5.2 前置代码

from appium import webdriver
# server 启动参数
desired_caps = {}
# 设备信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
# app的信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'

# 声明我们的driver对象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)

5.3 通过id定位

  • 方法:find_element_by_id(id_value) # id_value:为元素的id属性值
  • 业务场景:
    1. 进入设置页面
    2. 通过ID定位方式点击搜索按钮
  • 代码实现:
    driver.find_element_by_id("com.android.settings:id/search").click()
    driver.quit()
    

5.4 通过class定位

  • 方法:find_element_by_class_name(class_value) # class_value:为元素的class属性值
  • 业务场景:
    1. 进入设置页面
    2. 点击搜索按钮
    3. 通过class定位方式点击输入框的返回按钮
  • 代码实现:
# id 点击搜索按钮
driver.find_element_by_id("com.android.settings:id/search").click()
# class 点击输入框返回按钮
driver.find_element_by_class_name('android.widget.ImageButton').click()
driver.quit()

5.5 通过xpath定位

  • 方法:find_element_by_xpath(xpath_value) # xpath_value:为可以定位到元素的xpath语句
    android端xptah常用属性定位:
    1. id ://*[contains(@resource-id,'com.android.settings:id/search')]
    2. class ://*[contains(@class,'android.widget.ImageButton')]
    3. text ://*[contains(@text,'WLA')]
    模糊定位 contains(@key,value): value可以是部分值
  • 业务场景:
    1. 进入设置页面
    2. 点击WLAN菜单栏
  • 代码实现:
    # xpath 点击WLAN按钮
    driver.find_element_by_xpath("//*[contains(@text,'WLA')]").click()
    

5.6 定位一组元素,注意element -> elements

应用场景为元素值重复,无法通过元素属性直接定位到某个元素,只能通过elements方式来选择,返回一个定位对象的列表.

5.7 通过id方式定位一组元素

  • 方法: find_elements_by_id(id_value) # id_value:为元素的id属性值
  • 业务场景:
    1. 进入设置页面
    2. 点击WLAN菜单栏(id定位对象列表中第1个)
  • 代码实现:
    # 定位到一组元素
    title = driver.find_elements_by_id("com.android.settings:id/title")
    # 打印title类型,预期为list
    print(type(title))
    # 取title返回列表中的第一个定位对象,执行点击操作
    title[0].click()
    

5.8 通过class方式定位一组元素

  • 方法:find_elements_by_class_name(class_value) # class_value:为元素的class属性值
  • 业务场景:
    1.进入设置页面
    2.点击WLAN菜单栏(class定位对象列表中第3个)
  • 代码实现:
    title = driver.find_elements_by_class_name("android.widget.TextView")
    # 打印title类型,预期为list
    print(type(title))
    # 取title返回列表中的第一个定位对象,执行点击操作
    title[3].click()
    for index, item in enumerate(ele_list):
      print(index, item.text)  ```
    

5.9 通过xpath方式定位一组元素

  • 方法:find_elements_by_xpath(xpath_value) # xpath_value:为可以定位到元素的xpath语句
  • 业务场景:
    1. 进入设置页面
    2. 点击WLAN菜单栏(xpath中class属性定位对象列表中第3个)
  • 代码实现:
    # 定位到一组元素
    title = driver.find_elements_by_xpath("//*[contains(@class,'widget.TextView')]")
    # 打印title类型,预期为list
    print(type(title))
    # 取title返回列表中的第一个定位对象,执行点击操作
    title[3].click()
    

六、WebDriverWait 显示等待操作

在一个超时时间范围内,每隔一段时间去搜索一次元素是否存在,如果存在返回定位对象,如果不存在直到超时时间到达,报超时异常错误。

  • 方法:WebDriverWait(driver, timeout, poll_frequency).until(method)
    参数:
    1.driver:手机驱动对象
    2.timeout:搜索超时时间
    3.poll_frequency:每次搜索间隔时间,默认时间为0.5s
    4.method:定位方法(匿名函数)
  • 匿名函数:
    lambda x: x
    等价于python函数:
    def test(x):
    return x
  • 使用示例:
    WebDriverWait(driver, timeout, poll_frequency).until(lambda x:x.find_elements_by_id(id_value))
    
  • 解释:
    1.x传入值为:driver,所以才可以使用定位方法。
  • 函数运行过程:
    1.实例化WebDriverWait类,传入driver对象,之后driver对象被赋值给WebDriverWait的一个类变量:self._driver
    2.until为WebDriverWait类的方法,until传入method方法(即匿名函数),之后method方法会被传入self._driver
    3.搜索到元素后until返回定位对象,没有搜索到函数until返回超时异常错误.
  • 业务场景:
    1.进入设置页面
    2.通过ID定位方式点击搜索按钮
  • 代码实现:
    from selenium.webdriver.support.wait import WebDriverWait # 导入WebDriverWait  类
    # 超时时间为30s,每隔1秒搜索一次元素是否存在,如果元素存在返回定位对象并退出
    search_button = WebDriverWait(driver, 30, 1).until(lambda driver:driver.find_element_by_id("com.android.settings:id/search"))
    search_button.click()
    driver.quit()
    

七、APP元素信息操作API

本节讲介绍手机端元素信息的获取以及基本的输入操作。

7.1. 点击元素

ele.click()

7.2.发送数据到输入框

  • 方法:send_keys(vaue) # value:需要发送到输入框内的文本

  • 业务场景:
    1.打开设置
    2.点击搜索按钮
    3.输入内容abc

  • 代码实现:

    # 点击搜索按钮
    driver.find_element_by_id("com.android.settings:id/search").click()
    # 定位到输入框并输入abc
    driver.find_element_by_id("android:id/search_src_text").send_keys("abc")
    
  • 重点:大家可以将输入的abc 改成 输入中文,得到的结果:输入框无任何值输入且程序不会抱错
    解决输入中文问题:

      1.server 启动参数增加两个参数配置
          desired_caps['unicodeKeyboard'] = True
          desired_caps['resetKeyboard'] = True
    
      2.再次运行会发现运行成功
          # 点击搜索按钮
          driver.find_element_by_id("com.android.settings:id/search").click()
          # 定位到输入框并输入abc
          driver.find_element_by_id("android:id/search_src_text").send_keys("积云教育")
    

7.3. 清空输入框内容

  • 方法:clear()
  • 业务场景:
    1.打开设置
    2.点击搜索按钮
    3.输入内容abc
    4.删除已输入abc
  • 代码实现:
    # 点击搜索按钮
    driver.find_element_by_id("com.android.settings:id/search").click()
    # 定位到输入框并输入abc
    input_text = driver.find_element_by_id("android:id/search_src_text")
    # 输入abc
    input_text.send_keys("abc")
    time.sleep(1)
    # 删除abc
    input_text.clear()
    

7.4. 获取元素的文本内容

  • 方法: text
  • 业务场景:
    1.进入设置
    2.获取所有元素class属性为“android.widget.TextView”的文本内容
  • 代码实现:
    ele_list = driver.find_elements_by_class_name("android.widget.TextView")
    for e in ele_list:
        print(e.text)
    for index, item in enumerate(ele_list):
        print(index, item.text)
    
  • 执行结果:
      0 设置
      1
      2 移动数据网络已关闭
      3 无线和网络
      4 WLAN
      5 "guest"
      6 蓝牙
      7 已停用
      8 流量使用情况
      9 已使用 0 B 的数据
      10 更多
      11 设备
      12 显示
      13 自动调节亮度功能已关闭
      14 通知
      15 已允许所有应用发送通知
    

7.5. 获取元素的属性值

  • 方法: get_attribute(value) # value:元素的属性
    ⚠️ value='name' 返回content-desc / text属性值
    ⚠️ value='text' 返回text的属性值
    ⚠️ value='className' 返回 class属性值,只有 API=>18 才能支持
    ⚠️ value='resourceId' 返回 resource-id属性值,只有 API=>18 才能支持

  • 业务场景:
    1.进入设置
    2.获取搜索按钮的content-desc属性值

  • 代码实现:

    # 定位到搜索按钮
    get_value = driver.find_element_by_id("com.android.settings:id/search")
    print(get_value.get_attribute("content-desc"))
    执行结果:
            搜索
    

7.6. 获取元素在屏幕上的坐标

  • 方法:location
  • 业务场景:
    1.进入设置页面
    2.获取搜索按钮在屏幕的坐标位置
  • 代码实现:
# 定位到搜索按钮
get_value = driver.find_element_by_id("com.android.settings:id/search")
# 打印搜索按钮在屏幕上的坐标
print(get_value.location)
{'y': 44, 'x': 408}

7.7. 获取app包名和启动名

  • 获取包名方法:current_package
  • 获取启动名:current_activity
  • 业务场景:
    1.启动设置
    2.获取包名和启动名
  • 代码实现:
    print(driver.current_package)
    print(driver.current_activity)
    
  • 执行结果:
    com.tencent.news
    .activity.SplashActivity
    

八、APP元素事件操作API

8.1. 前置代码

from appium import webdriver
# server 启动参数
desired_caps = {}
# 设备信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
# app的信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'

# 声明我们的driver对象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)

8.2. swip滑动事件

⚠️从一个坐标位置滑动到另一个坐标位置,只能是两个点之间的滑动

  • 方法:swipe(start_x, start_y, end_x, end_y, duration=None)
  • 参数:
    1.start_x:起点X轴坐标
    2.start_y:起点Y轴坐标
    3.end_x: 终点X轴坐标
    4.end_y,: 终点Y轴坐标
    5.duration: 滑动这个操作一共持续的时间长度,单位:ms
    • 业务场景:
      1.进入设置
      2.从坐标(148,659)滑动到坐标(148,248)
  • 代码实现:
    # 滑动没有持续时间
    driver.swipe(188,659,148,248)
    # 滑动持续5秒的时间
    driver.swipe(188,659,148,248,5000)
    

8.3. scroll滑动事件

⚠️ 从一个元素滑动到另一个元素,直到页面自动停止

  • 方法:scroll(origin_el, destination_el)
  • 参数:
    1.origin_el:滑动开始的元素
    2.destination_el:滑动结束的元素
  • 业务场景:
    1.进入设置页
    2.模拟手指从存储菜单位置 到 WLAN菜单位置的上滑操作
  • 代码实现:
    # 定位到存储菜单栏
    el1 = driver.find_element_by_xpath("//*[contains(@text,'存储')]")
    # 定位到WLAN菜单栏
    el2 = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
    # 执行滑动操作
    driver.scroll(el1,el2)
    

8.4. drag拖拽事件

⚠️ 从一个元素滑动到另一个元素,第二个元素替代第一个元素原本屏幕上的位置

  • 方法:drag_and_drop(origin_el, destination_el)
  • 参数:
    1.origin_el:滑动开始的元素
    2.destination_el:滑动结束的元素
  • 业务场景:
    1.进入设置页
    2.模拟手指将存储菜单 滑动到 WLAN菜单栏位置
  • 代码实现:
    # 定位到存储菜单栏
    el1 = driver.find_element_by_xpath("//*[contains(@text,'存储')]")
    # 定位到WLAN菜单栏
    el2 = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
    # 执行滑动操作
    driver.drag_and_drop(el1,el2)
    

8.5. 应用置于后台事件

APP放置后台,模拟热启动

  • 方法:background_app(seconds)
  • 参数:
    1.seconds:停留在后台的时间,单位:秒
  • 业务场景:
    1.进入设置页
    2.将APP置于后台5s
  • 代码实现:
    driver.background_app(5)
    
  • 效果:
    app置于后台5s后,再次展示当前页面
    

九、APP模拟手势高级操作

TouchAction是AppiumDriver的辅助类,主要针对手势操作,比如滑动、长按、拖动等,原理是将一系列的动作放在一个链条中发送到服务器,服务器接受到该链条后,解析各个动作,逐个执行。

9.1. 前置代码

from appium import webdriver
# server 启动参数
desired_caps = {}
# 设备信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
# app的信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'

# 声明我们的driver对象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)

⚠️ 所有手势都要通过执行函数才会运行.

9.2. 手指轻敲操作

模拟手指轻敲一下屏幕操作

  • 方法:tap(element=None, x=None, y=None)
  • 方法:perform() # 发送命令到服务器执行操作
  • 参数:
    1.element:被定位到的元素
    2.x:相对于元素左上角的坐标,通常会使用元素的X轴坐标
    3.y:通常会使用元素的Y轴坐标
  • 业务场景:
    1.进入设置
    2.点击WLAN选项
  • 代码实现:
    # 通过元素定位方式敲击屏幕
    el = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
    TouchAction(driver).tap(el).perform()
    
    # 通过坐标方式敲击屏幕,WLAN坐标:x=155,y=250
    # TouchAction(driver).tap(x=155,y=250).perform()
    

9.3. 手指按操作

模拟手指按下屏幕,按就要对应着离开.

  • 方法:press(el=None, x=None, y=None)
  • 方法:release() # 结束动作,手指离开屏幕
  • 参数:
    1.element:被定位到的元素
    2.x:通常会使用元素的X轴坐标
    3.y:通常会使用元素的Y轴坐标
  • 业务场景:
    1.进入设置
    2.点击WLAN选项
  • 代码实现:
    # 通过元素定位方式按下屏幕
    el = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
    TouchAction(driver).press(el).release().perform()
    
    # 通过坐标方式按下屏幕,WLAN坐标:x=155,y=250
    # TouchAction(driver).press(x=155,y=250).release().perform()
    

9.4. 等待操作

  • 方法:wait(ms=0)
  • 参数:
    ms:暂停的毫秒数
  • 业务场景:
    1.进入设置
    2.点击WLAN选项
    3.长按WiredSSID选项5秒
  • 代码实现:
    # 点击WLAN
    driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").click()
    # 定位到WiredSSID
    el =driver.find_element_by_id("android:id/title")
    # 通过元素定位方式长按元素
    TouchAction(driver).press(el).wait(5000).perform()
    
    # 通过坐标方式模拟长按元素
    # 添加等待(有长按)/不添加等待(无长按效果)
    # TouchAction(driver).press(x=770,y=667).wait(5000).release().perform()
    

9.5. 手指长按操作

模拟手机按下屏幕一段时间,按就要对应着离开.

  • 方法:long_press(el=None, x=None, y=None, duration=1000)
  • 参数:
    1.element:被定位到的元素
    2.x:通常会使用元素的X轴坐标
    3.y:通常会使用元素的Y轴坐标
    4.duration:持续时间,默认为1000ms
  • 业务场景:
    1.进入设置
    2.点击WLAN选项
    3.长按WiredSSID选项5秒
  • 代码实现:
    # 点击WLAN
    driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").click()
    # 定位到WiredSSID
    el =driver.find_element_by_id("android:id/title")
    # 通过元素定位方式长按元素
    TouchAction(driver).long_press(el,duration=5000).release().perform()
    
    # 通过坐标方式长按元素,WiredSSID坐标:x=770,y=667
    # 添加等待(有长按)/不添加等待(无长按效果)
    # TouchAction(driver).long_press(x=770,y=667).perform()
    

9.6. 手指移动操作

模拟手机的滑动操作

  • 方法:move_to(el=None, x=None, y=None)
  • 参数:
    1.el:定位的元素
    2.x:相对于前一个元素的X轴偏移量
    3.y:相对于前一个元素的Y轴偏移量
  • 业务场景1:
    1.进入设置
    2.向上滑动屏幕
  • 代码实现:
    # 定位到存储
    el = driver.find_element_by_xpath("//*[contains(@text,'存储')]")
    # 定位到更多
    el1 = driver.find_element_by_xpath("//*[contains(@text,'更多')]")
    # 元素方式滑动
    TouchAction(driver).press(el).wait(2000).move_to(el1).release().perform()
    # 坐标的方式滑动
    # TouchAction(driver).press(x=240,y=600).wait(100).move_to(x=240,y=100).release().perform()
    # 注意press连接一个move_to实际调用的是swip方法,可在log中查询,不要给相对坐标。
    
  • 业务场景2:
    1.进入设置
    2.向上滑动屏幕到可见"安全"选项
    3.进入到安全
    4.点击屏幕锁定方式
    5.点击图案
    6.绘制图案
  • 代码实现:
    # 定位到WLAN
    el1 = driver.find_element(By.XPATH, "//*[contains(@text,'WLAN')]")
    # 定位到存储
    el2 = driver.find_element(By.XPATH, "//*[contains(@text,'应用')]")
    # 存储上滑到WLAN
    driver.drag_and_drop(el2, el1)
    # 定位到用户
    el3 = driver.find_element(By.XPATH, "//*[contains(@text,'用户')]")
    # 注意 这次使用drag_and_drop方法,传入的"存储定位"仍使用其原始在屏幕上的位置,所以是由存储滑动到用户才可以上滑,否则需要重新"定位存储"
    # 存储上滑倒用户位置
    driver.drag_and_drop(el3, el2)
    # 点击安全按钮
    driver.find_element(By.XPATH, "//*[contains(@text,'安全')]").click()
    # 点击屏幕锁定方式按钮
    driver.implicitly_wait(3)
    driver.find_element(By.XPATH, "//*[contains(@text,'屏幕锁定')]").click()
    # 点击图案按钮
    driver.implicitly_wait(3)
    driver.find_element(By.XPATH, "//*[contains(@text,'图案')]").click()
    # 绘制图案四个坐标 1:(244,967) 2:(723,967) 3:(723,1442) 4:(244,1916)
    # time.sleep(10)
    WebDriverWait(driver, 10, 0.5).until(lambda x:x.find_element(By.ID,'com.android.settings:id/lockPattern'))
    TouchAction(driver).press(x=182, y=771).wait(100).move_to(x=716, y=771).wait(100) \
      .move_to(x=182, y=1300).move_to(x=716, y=1300).release().perform()
    time.sleep(2)
    driver.find_element(By.ID,'com.android.settings:id/footerRightButton').click()
    

十、手机操作API

针对手机的一些常用设置功能进行操作.

10.1. 前置代码

from appium import webdriver
# server 启动参数
desired_caps = {}
# 设备信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
# app的信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'

# 声明我们的driver对象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)

10.2. 获取手机时间

  • 方法:device_time
  • 代码实现:
    # 获取当前手机的时间
    print(driver.device_time)
    
  • 执行结果:
    Wed Dec 27 08:52:45 EST 2017
    

10.3. 获取手机的宽高

获取手机的宽高,可以根据宽高做一些坐标的操作

  • 方法:get_window_size()
  • 代码实现:
print(driver.get_window_size())
  • 执行结果:
{'height': 800, 'width': 480}

10.4. 发送键到设备

模拟系统键值的操作,比如操作home键,音量键,返回键等。

  • 参数:
    keycode:发送给设备的关键代码
    metastate:关于被发送的关键代码的元信息,一般为默认值
  • 业务场景:
    1.打开设置
    2.按多次音量增加键
  • 代码实现:
    for i in range(3):
        driver.keyevent(24)
    

Appium---Android的keycode键值

adb命令使用
adb shell input keyevent XX(EventCode) #输入对应的键值
adb shell input text "www.baidu.com"
#向浏览器发送文本

EventCode KeyEvent EventName
0 KEYCODE_UNKNOWN 未知键
1 KEYCODE_SOFT_LEFT 左键
2 KEYCODE_SOFT_RIGHT 右键
3 KEYCODE_HOME Home键
4 KEYCODE_BACK 返回键
5 KEYCODE_CALL 拨号键
6 KEYCODE_ENDCALL 挂机键
7 KEYCODE_0 按键“0”
8 KEYCODE_1 按键“1”
9 KEYCODE_2 按键“2”
10 KEYCODE_3 按键“3”
11 KEYCODE_4 按键“4”
12 KEYCODE_5 按键“5”
13 KEYCODE_6 按键“6”
14 KEYCODE_7 按键“7”
15 KEYCODE_8 按键“8”
16 KEYCODE_9 按键“9”
17 KEYCODE_STAR 按键“*”
18 KEYCODE_POUND 按键“#”
19 KEYCODE_DPAD_UP 导航键 向上
20 KEYCODE_DPAD_DOWN 导航键 向下
21 KEYCODE_DPAD_LEFT 导航键 向左
22 KEYCODE_DPAD_RIGHT 导航键 向右
23 KEYCODE_DPAD_CENTER 导航键 确定
24 KEYCODE_VOLUME_UP 音量键加
25 KEYCODE_VOLUME_DOWN 音量键减
26 KEYCODE_POWER 电源键
27 KEYCODE_CAMERA 相机键
28 KEYCODE_CLEAR 清除键
29 KEYCODE_A 按键“A”
30 KEYCODE_B 按键“B”
31 KEYCODE_C 按键“C”
32 KEYCODE_D 按键“D”
33 KEYCODE_E 按键“E”
34 KEYCODE_F 按键“F”
35 KEYCODE_G 按键“G”
36 KEYCODE_H 按键“H”
37 KEYCODE_I 按键“I”
38 KEYCODE_J 按键“J”
39 KEYCODE_K 按键“K”
40 KEYCODE_L 按键“L”
41 KEYCODE_M 按键“M”
42 KEYCODE_N 按键“N”
43 KEYCODE_O 按键“O”
44 KEYCODE_P 按键“P”
45 KEYCODE_Q 按键“Q”
46 KEYCODE_R 按键“R”
47 KEYCODE_S 按键“S”
48 KEYCODE_T 按键“T”
49 KEYCODE_U 按键“U”
50 KEYCODE_V 按键“V”
51 KEYCODE_W 按键“W”
52 KEYCODE_X 按键“X”
53 KEYCODE_Y 按键“Y”
54 KEYCODE_Z 按键“Z”
55 KEYCODE_COMMA 按键“,”
56 KEYCODE_PERIOD 按键‘.’
57 KEYCODE_ALT_LEFT 组合键 Alt+Left
58 KEYCODE_ALT_RIGHT 组合键 Alt+Right
59 KEYCODE_SHIFT_LEFT 组合键 Shift+Left
60 KEYCODE_SHIFT_RIGHT 组合键 Shift+Left
61 KEYCODE_TAB Tab键
62 KEYCODE_SPACE 空格键
63 KEYCODE_SYM 选择输入法
64 KEYCODE_EXPLORER 浏览器
65 KEYCODE_ENVELOPE 邮件
66 KEYCODE_ENTER 回车键
67 KEYCODE_DEL 退格键
68 KEYCODE_GRAVE 按键‘`’
69 KEYCODE_MINUS 按键‘-’
70 KEYCODE_EQUALS 按键‘=’
71 KEYCODE_LEFT_BRACKET 按键‘[’
72 KEYCODE_RIGHT_BRACKET 按键‘]’
73 KEYCODE_BACKSLASH 按键‘\’
74 KEYCODE_SEMICOLON 按键‘,’
75 KEYCODE_APOSTROPHE 按键‘'’(单引号)
76 KEYCODE_SLASH 按键‘/’
77 KEYCODE_AT 按键‘@’
78 KEYCODE_NUM 按键Number modifier
79 KEYCODE_HEADSETHOOK 按键Headset Hook
80 KEYCODE_FOCUS 拍照对焦键
81 KEYCODE_PLUS 按键‘+’
82 KEYCODE_MENU 菜单键
83 KEYCODE_NOTIFICATION 通知键
84 KEYCODE_SEARCH 搜索键
85 TAG_LAST_KEYCODE

10.5. 操作手机通知栏

打开手机的通知栏,可以获取通知栏的相关信息和元素操作

  • 方法:open_notifications()
  • 业务场景:
    1.启动设置
    2.打开通知栏
  • 代码实现:
driver.open_notifications()

10.6. 获取手机当前网络

获取手机当前连接的网络

  • 方法:network_connection
  • 业务场景:获取手机当前网络模式
  • 代码实现:
print(driver.network_connection)
  • 执行结果:
6
Value (Alias) Data Wifi Airplane Mode
0 (None) 0 0 0
1 (Airplane Mode) 0 0 1
2 (Wifi only) 0 1 0
4 (Data only) 1 0 0
6 (All network on) 1 1 0

10.7. 设置手机网络

更改手机的网络模式,模拟特殊网络情况下的测试用例

  • 方法:set_network_connection(connectionType)
  • 参数:
    connectionType:需要被设置成为的网络类型
  • 业务场景:
    1.启动设置
    2.设置手机网络为飞行模式
  • 代码实现:
driver.set_network_connection(1)

10.8. 手机截图

截取手机当前屏幕,保存指定格式图片到设定位置

  • 方法:get_screenshot_as_file(filename)
  • 参数:
    filename:指定路径下,指定格式的图片.
  • 业务场景:
    1.打开设置页面
    2.截图当前页面保存到当前目录,命名为screen.png
  • 代码实现:
    import os
    driver.get_screenshot_as_file(os.getcwd() + os.sep + './screen.png')
    
  • 执行结果:
    当前目录下会生成screen.png文件

十一、脚本录制

11.1. 认识界面

image.png

11.2. 点击开始录制按键开始录制脚本

  1. 点击顶部导航栏左侧第一个“选择元素”按键选定搜索栏,然后点击右边点“点击”按键进行操作(录制过程就是先选择录制窗口左边的APP元素,然后录制窗口右边的操作方式)。

  2. 录制完成后点击“停止录制”按键,录制窗口右上角会同步显示操作代码,选择代码类型,将模板代码转换成正式代码,复制代码到Pycharm。

  3. 代码复制到pycharm后,最好是在每个操作或者页面切换处加上等待时间,否则会因为网速、APP设计问题或者其他原因,无法及时到达下一个页面,导致APPIUM无法获取页面元素而定位元素失败,在pycharm运行时报错。代码编辑好后点击pycharm的运行按键,APPium就会在手机上面自动运行脚本了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容