python app自动化入门

3,685 阅读16分钟

appium概述

appium是一个开源工具,用于自动化ios手机、android手机和windows桌面平台的原生、移动web和混合应用。

appium是跨平台的: 允许你用同样的api对多平台写测试,做到ios、android和windows测试套件之间复用代码。

原生应用: 指那些用ios、android或者windows SDK编写的应用

移动web应用: 是用移动端浏览器访问的应用(appium支持ios的safari、chrome和android上内置的浏览器)

混合应用: 带有一个webview的包装器,用来和web内容交互的原生控件

官网: appium.io/

appium python -- appium 服务端 -- 设备

appium 理念

Appium根据以下四个原则概述的理念来满足移动自动化需求:

  • 您无需重新编译或以任何方式对其进行修改即可使其自动化。

  • 您不应该被锁定在特定的语言或框架中来编写和运行测试。

  • 当涉及到自动化API时,移动自动化框架不应重新发明轮子。

  • 移动自动化框架应该在精神,实践和名称上都是开源的。

appium 设计

appium 工作原理

使用android和ios自带的自动化框架api为什么还要使用appium呢?

  • 因为android的开发语言是java,ios开发语言是Object C,如果要使用他们的api,必须要学习java和OC,所以,在没有appium之前,自动化测试确实也是这么做的。做android的自动化测试要写一套java代码,做ios测试要写一套Object C代码

  • appium跨平台,一套python代码,既可以在ios上运行,也可以在android上运行

不同的系统版本,自带的自动化框架都有所不同:

  • 要使用appium跟移动设备通信,首先要确定设备自带的自动化框架是什么
  • appium与设备通信的原理如下:
    • appium监听4723端口
    • python代码通过http请求,发送给appium,appium转发请求,并转化成移动设备可以识别的命令,Bootstrap.jar监听4724端口接收命令,调用UIAutomator驱动移动设备操作。

appium环境搭建

android自动化环境搭建

  • node.js

    appium server的运行环境

  • appium server

    • 方式一:npm install -g appium

      安装appium的难点主要在于:

      selendroid、uiaotomator 、chromedriver下载难

      可通过设置代理或淘宝镜像

      淘宝镜像:(使用淘宝镜像在下载selendroid仍然需要等待一段时间,耐心一些)

      #安装cnpm
      npm install -g cnpm --registry=https://registry.npm.taobao.org
      #通过cnpm命令安装appium
      cnpm install -g  appium
      

      cnpm实际是npm一大串命令的简写

    • 方式二:官网下载安装appium desketop

      下载地址:github.com/appium/appi…

  • jdk 1.8以上

  • android sdk

    • 方式一:安装android studio

    • 方式二:安装android adt

    • 都会自带安装android sdk

      • tools/bin 下的uiautomatorviewer,用于元素定位
      • platform-tools下的adb命令
      • build-tools下的aapt命令
    • 配置andeoid环境变量

      # 配置android环境变量
      export ANDROID_HOME=/Users/leitianxiao/Library/Android/sdk
      export PATH=$PATH:${ANDROID_HOME}/tools
      export PATH=$PATH:${ANDROID_HOME}/platform-tools
      

      命令:adb version检查环境变量是否配置成功

  • 模拟器、真机

    • 真机需开启调试模式
    • 模拟器(默认是有root权限的):夜神、海马、逍遥、genymotion

一个简单的app自动化demo

  • 启动模拟器或者连接真机:通过adb devices命令确认连接

  • pip2 install --user Appium-Python-Client

    • 导入安装包from appium import webdriver
  • 提供模拟器或真机的一些基础信息

    • 平台类型
    • 平台版本号
    • app包名
    • app入口activity
    • 设备名称

    如何提供呢?

    Desired Capabilities: appium.io/docs/en/wri…

    desired_caps={}
    # 平台类型
    desired_caps["platformName"]="Android"
    # 平台版本号
    desired_caps["platformVersion"]="8.0"
    # 设备名称
    desired_caps["deviceName"]="Android Emulator"
    # app包名
    desired_caps["appPackage"]="com.tagphi.littlebee"
    # app入口activity
    desired_caps["appActivity"]="com.tagphi.littlebee.ui.login.WelcomeActivity"
    

    如何获取appPackage、appActivity?

    aapt命令:aapt dump badging apk文件路径(包含文件名)

    aapt默认没有配置到环境变量中,可以选择配置到环境变量中,也可以选择在aapt文件下进行该命令。aapt的地址是安卓环境变量下的...sdk/build-tools/xxx/aapt

    • 获取appPackage
    • 获取appActivity
  • 启动app

    #建立与appium server的连接,前提:启动appium desketop
    #将desired_caps发送给appium server,打开app
    driver=webdriver.Remote("http://127.0.0.1:4723/wd/hub",desired_caps)
    

    run这个.py文件,即可启动对应的app

    运行代码之前:

    1.appium server启动,处于监听状态

    2.模拟器/真机必须能够被电脑识别,即adb devices能识别到该操作设备

完成一个app的简单启动,在正式开始写app自动化之前,还需要学习adb命令、安卓控件、UIAutomator等

adb的使用和配置

adb介绍

  • 什么是adb:adb(Android Debug Bridge),是android sdk的一个工具,安卓调试桥。
  • adb是用来连接pc和android设备的桥梁,要有adb作为两者的维系,才能让用户在电脑上对手机进行全面的操作。
  • android的初衷是adb这样一个工具来协助开发人员在开发andorid应用过程中更快的的调试apk,因此adb具有安装、卸载apk、拷贝推送文件、查看设备硬件信息、查看应用占用资源、在设备上执行shell命令等功能。
  • 模拟器一般是自带root权限的,但是真机使用adb命令需要开启在手机上开启开发者模式-USB调试

adb命令

  • adb devices 检测连接到电脑的adb设备,这个是使用adb命令的基础,因为首先需要设备连接到电脑才可进行后续其他操作。
  • adb --help 查看帮助手册
  • adb logcat 打印log信息,搭配重定向>>(追加)或者>(覆盖重写),将log输出到指定文件里
  • adb pull <手机路径> <本地路径> 从手机中拉取信息放在本地电脑上
  • adb push <本地路径> <手机路径> 从本地推送信息到手机上
  • adb shell 登录设备shell(命令行的人机界面),ll ls命令都可以使用,进入到linux环境,相当与远程命令。
  • adb install xxx.apk 安装app
  • adb uninstall 应用包名 卸载app
    • 多设备时,指定设备进行安装,使用命令adb -s 设备id uninstall 应用包名
      adb -s 192.168.56.101:5555 uninstall com.tagphi.littlebee
  • adb shell dumpsys activity|find "mFocusedActivity" 查看前台应用activity名,即当前页面的activity
  • adb connect/disconnect 通过wifi进行远程连接手机进行调试
  • adb kill-server 终止adb服务
  • adb start-server 启动adb服务,通常在adb遇到问题的时候,与adb kill-server一起使用
  • adb shell pm list packages 列出所有包名
    • -f 列出所有apk路径及包名
    • -s 列出系统apk路径及包名
    • -3 列出用户自己安装的apk路径及包名 adb shell pm list packages -3

UIAutomator

UIAutomator介绍

UI自动化测试框架,安卓移动app。要求安卓4.3以上

  • 提供一系列api:执行UI测试在系统或者第三方app上
  • 允许在被测试的设备上执行操作,比如打开系统设置菜单
  • 适合编写黑盒测试自动化 UIAutomator框架的特点:
  • 元素定位:UI Automator Viewer 扫描、分析待测应用的UI组件的图像工具
  • 元素操作:Accessing device state 在目标设备和app上的各种操作
  • 元素识别:UI Automator APIs 在多个应用程序中捕获和操作UI组件

UI Automator Viewer

安装sdk时,默认安装在tools/bin目录下,双击启动uiautomatorviewer。只能识别andorid原生控件,无法识别web网页之类的。 确保设备与pc已建立连接。

  • 截图按钮:点击截图按钮,会对当前页面进行截图
  • 截图区域:类似与网页端的f12 element模式,选择不同的区域,定位区域有对应的
  • 页面的源码和元素的源码(只能识别原生控件);xxxLayout是安卓中的布局模式,后面跟的是坐标,起始坐标和终止坐标。左上角是起始坐标[0,0],右下角是终止坐标[768,1184],x轴向右越来越大,y轴向下越来越大。
  • 类似于html,也是有层级关系的
  • Node Detail 选中元素的属性
    • text:文本内容
    • resource-id:不一定唯一
    • class:属性的名字
    • package:包名
    • content-desc:描述内容,对于需要进行语音播报的用户,会播报这里面的内容,一般对于一些有视觉障碍的群体使用时会用到。
    • checkable:能不能被选中
    • checked:是否被选中
    • clickable:是否可点击
    • enable:元素是否可用,比如文本框元素,是否可输入
    • focusable:是否能focus在这个元素上
    • focused:是否focus在这个元素上
    • scrollable:是否可滚动
    • long-clickable:是否能长按
    • password:是否是密码
    • selected:是否是下拉列表
    • bounds:起始坐标和终点坐标

app页面元素定位

定位方式(五种)

  • 通过id定位:resource-id

    • driver.find_element_by_id("com.tagphi.littlebee:id/et_phone_input_getcode")
  • 通过ClassName定位:classname

    • driver.find_element_by_class_name("android.widget.TextView")
  • 通过AccessibilityId定位:content-desc

    • 导入包from appium.webdriver.common.mobileby import MobileBy
    • driver.find_element_by_accessibility_id(""),对应的值是元素的content-desc属性的值,所以不是所有的元素都可以使用这个AccessibilityId定位
  • 通过AndroidUIAutomato定位

    • 官方文档:developer.android.com/training/te… (需要翻墙)

    • UI Automator API使您可以编写健壮的测试,而无需了解目标应用的实现细节。可以使用以下API来捕获和操纵跨多个应用程序的UI组件:

      • UiCollection:枚举容器的UI元素,以便通过其可见文本或content-description属性计数或定位子元素。
      • UiObject:代表在设备上可见的UI元素
      • UiScrollable:提供对在可滚动UI容器中搜索项目的支持。
      • UiSelector:代表对设备上一个或多个目标UI元素的查询
      • Configurator:允许您设置运行UI Automator测试的关键参数。
    • 使用UIAutomato中的UISelector类来处理元素定位

      • 在python客户端appium库中通过uiautomator来获取元素的方法: driver.find_element_by_android_uiautomator("定位表达式")
      • 实例化一个UISelector对象,然后通过实例(文档中的方法)调用接口。new UiSelector().函数名称("定位表达式")
      • 示例: driver.find_element_by_android_uiautomator('new UiSelector().resouceId(com.tagphi.littlebee:id/et_phone_input_getcode).text("暂不同意")')
    • 什么时候使用AndroidUIAutomato定位?前几种方式都无法定位,使用自己的框架定位方式,效率很高

  • 通过xpath定位

    • 升级一个uiautomatorviewer增强版,自动带有xpath属性
    • app中定位少使用xpath,第四种基本都能搞定
    • 如果这几种方式都无法定位,需要使用坐标定位

作业:启动自己公司的app,并实现登录

实战会遇到的问题:

  • 没有加等待时间,因为元素没有加载出来而报错,解决方法:给新页面加等待时间

    • 导入WebDriverWait、MobileBy

      from selenium.webdriver.support.wait import WebDriverWait
      from appium.webdriver.common.mobileby import MobileBy
      from selenium.webdriver.support import expected_conditions as EC
      
    • 设置等待

      WebDriverWait(driver, 20).until(EC.visibility_of_element_located((MobileBy.ID,"com.tagphi.littlebee:id/tv_confirm_doublebtn_dialog")))
      
  • 手机键盘遮挡元素,解决方法:Desired Capabilities中有一个参数是可以隐藏键盘的

appium 常用API

滑动屏幕 swipe

滑动接口: swipe(起始X,起始Y,结束X,起始Y)

结束x-起始x:x轴滑动的距离

结束y-起始y:y轴滑动的距离

Q:手机的屏幕尺寸有很多,如何兼容? 原理: 1.获取设备的屏幕大小 2.再设置滑动距离与屏幕大小的百分比 3.调用滑动接口执行滑动操作

获取当前窗口 :get_window_size:返回窗口的高和宽

滑动接口:swipe(起始X,起始Y,结束X,起始Y,duration=None),duration-滑动的时间,单位是毫秒

#TODO:同样需要设置等待,等待页面元素加载出来再进行滑动操作

#获取窗口的height、width
size=driver.get_window_size()

start_x=size["width"] * 0.9
start_y=size["height"] * 0.5
end_x=size["width"] * 0.1 # 滑屏最好超过80%
end_y=start_y

# 从右往左滑
driver.swipe(start_x,start_y,end_x,end_y,200)

# 从左往右滑
driver.swipe(end_x,end_y,start_x,start_y,200)

# 从下往上滑 ,X轴不变 (start_x,start_y,end_x,end_y)
driver.swipe(size["width"] * 0.5,size["height"] * 0.9,size["width"] * 0.5,size["height"] * 0.1)

# 从上往下滑
driver.swipe(size["width"] * 0.5,size["height"] * 0.1,size["width"] * 0.5,size["height"] * 0.9)

触屏 TouchAction类

将一系列的动作放在一个链条中,然后将该链条传递给服务器。服务器接受到该链条后,解析各个动作,逐个执行。

  • 短按 press
  • 长按 longPress
  • 点击 tap
  • 移动到 move to :x,y为相对上一个坐标的距离
  • 等待 wait
  • 释放 release
  • 执行 perform
  • 取消 cancer

示例:

常见的手势密码:按住-分别滑动到各个点-释放

1.确定各个点的位置:如果这几个点是不同的id,那可以通过id定位;但是有可能会遇到9个点是相同的id,那么就需要通过坐标定位,所以这里介绍下通过坐标定位。 2.选择坐标:选在图案的中心,这样即使定位出现偏差,也能保证还在这个图案中,不会越界。 3.开发者模式可以开启坐标

各个点的坐标:(147,378) (359.378) (571,378) ....但是这样写代码,如果换了一个不同屏幕尺寸的设备就会失败,所以此处采用滑屏思想,用百分比、相对距离等

如图,对于这个红框view是一个正方形,可以把它的长度、宽度6等分。假设红框的起点坐标是(x,y),第一个点的坐标是(x+(1/6)\*x , y+(1/6)*x)

from appium.webdriver.common.touch_action import TouchAction

from appium import webdriver

# 元素的大小
ele=driver.find_element_by_id("")
size=ele.size
# 均分的布长,因为是正方形,所以x,y轴上的布长都一样
step=size["width"]/6
# 元素的起点坐标
ori=ele.location
# 元素第一个点坐标
point01=(ori["x"]+step,ori["y"]+step)
# 元素第二个点坐标
point02=(ori["x"]+step*3,ori["y"]+step)
# 元素第三个点坐标
point03=(ori["x"]+step*5,ori["y"]+step)
# 元素第四个坐标
point04=(ori["x"]+step*3,ori["y"]+step*3)
# 元素第五个坐标
point05=(ori["x"]+step*5,ori["y"]+step*3)
# 操作
TouchAction(driver).press(x=point01[0],y=point01[1]).wait(200).\ 
    move_to(x=point02[0],y=point02[1]).wait(200).\
    move_to(x=point03[0],y=point03[1]).wait(200).\
    move_to(x=point04[0],y=point04[1]).wait(200).\
    move_to(x=point05[0],y=point05[1]).wait(200).\
    release().\  # 释放
    perform()  # 执行

低版本的appium可能会有一个报错,越界,因为低版本的appium的move_to是相对坐标,而我们在这里写的是绝对坐标。此时move\_to(x=2*step,y=0)

toast提示信息获取

要获取toast信息需要满足以下要求:

1.appium server版本1.6.3+以上才支持toast获取

2.代码中必须执行automationName为UIAutomator2

3.UIAutomator2只支持安卓5.0+

4.要求配置jdk1.8 64位以上,配置好JAVA_HOME和path

示例:

# 在desired_caps中新增aotomationName为UIAutomator2,高版本的appium会自动切换到UIAutomator2

desired_caps["automationName"]="UIAutomator2"

# 到达出现toast的步骤,比如不输入用户名和密码,会弹出toast提示:手机号或密码不能为空

# 通过xpath定位
loc=(MobileBy.XPATH,"//*[contains(@text,"{}")]".format("手机号或密码不能为空"))

# 等待
try:
    WebDriverWait(driver,10,0.02).util(EC.presence_of_element_located(loc))
    print driver.find_element_by_xpath("//*[contains(@text,"{}")]".format("手机号或密码不能为空")).text)
except:
    print "没有找到匹配的toast"

使用driverWait方法中,请用presence of element_located 不要用visibility_of_element_located,对toast的可见处理并不支持,会直接报错

混合应用-h5

native&web&hybird 简介

目前主流的应用程序大致分为3类,Web App(网页应用)、Hybird App(混合应用)、Native App(原生应用)

怎么来分辨一个app页面是native还是web?两种方法

方法一:

1.在手机/模拟器开启开发者选项

2.开发者选项中勾选显示布局边界再返回app界面

3.如果app是web界面,那界面 不会有布局边界显示,如果有则说明是native的界面

  • 开发者选项-显示布局边界

  • 布局界面显示,就是native界面

方法二:

通过uiautomotorviewer截图,如果class属性是android.webkit.WebView,就是一个html页面。uiautomotorviewer是无法捕获html上的元素的。

这样会引发几个问题:

  • 如何获取到html上的元素、源码
  • 驱动html的自动化需要搭建环境
  • 一个是安卓原生控件,一个是html页面,如果要操作html页面,还需要切换到html页面,需要进行一个切换操作

hybird混合应用自动化方案

基于UIAutomator+Chromedriver

navite部分则uiautomator、weview部分走chromedriver,二者结合

  • 要求

    • Android 4.4+
    • webview必须为debug版本
      • debug模式如何来?

        app打包时,需要开发开启webview的debug属性setWebContentDebugEnable(true)。但是有的真机可能还是无法获取webview,官方给出答案是root,然后再去获取,实际上不同的厂商权限还是不同,有的厂商不需root。

  • 获取webview页面的三种方式

    • chrome://inspect,需要梯子

      • 浏览器输入chrome://inspect 获取webview

      • 点击inspect,进行元素定位和识别(没有梯子不显示内容)

    • 使用driver.page_source获取html页面

      • 切换到html页面,通过driver.page_source获取html页面的源码,保存在本地,再用浏览器打开进行元素定位、元素识别
    • 找开发人员要源文件

      • 找开发
    • uc-devtools,UC开发者工具,不需要梯子,所以常用这个

  • 驱动html自动化环境搭建

    • webview版本号,需要下载对应版本的chromedriver,放在对应的路径上(没找到,以后补充)

      下载地址:npm.taobao.org/mirrors/chr… ,在notes文件中查询支持的版本

      ps:这里可能存在的问题,webvview对应的chromedriver已经正确存放,但是appium报错说chromedriver版本太旧。解决:appium-desktop中的Advanced的Chromedriver Binary Path,把chromedriver存在其他路径,通过Chromedriver Binary Path引入。如果仍然报错,在保证不是代码问题的情况下,更换appium的版本,因为这是appium的问题,某些版本是这个样子。
      
  • 原生控件切换到webview

    切换到webview 前提:代码可以识别到webview,这需要开启app的webview debug属性,使用context获取webview 中文叫上下文,相当与web端的窗口

    • 列出所有的上下文:driver.contexts

    • 当前上下文:driver.current_context

    • 切换至默认上下文: driver.switch_to.context(None) 默认的原生控件

    • 当前Activity: driver.current_activity 获取当前的Activity,仅支持安卓

    • 当前的包名:driver.current_packge 获取当前的Package,仅支持安卓

    • 示例

    # 1.先列出所有的context
    cons=driver.contexts # 列表
    print cons
    
    # 2.切换,webview一定是出现在最后的
    driver.switch_to.context(cons[-1])
    
    # 3.切换后,当前的操作对象是html页面
    #等待元素可见
    WebDriverWait(driver,20).until(EC.visibility_of_element_located(MobileBy.XPATH,"//button[@class='buttom-btn buy']"))
    #操作元素
    driver.find_element_by_xpath("//button[@class='buttom-btn buy']").click()
    
    

小程序测试

小程序测试简单教程