Appium App自动化测试框架安装和使用

   日期:2020-05-31     浏览:181    评论:0    
核心提示:Appium构成和工作原理前言:每一篇博客我都想完成一个前言,第一是明确我对写这篇博客得态度,必须要认真和用心,另外作为技术分享,我也希望能帮助到一些伙伴有一些技术性得提升,测试 “点点点” 得时代已经结束,毕竟现在是智能化、自动化的时代,我们也必须要用技术武装自己,这样才能不被时代抛弃(明明可以靠脸吃饭的我,硬是吃成了一个胖子)。adb构成client端, 在电脑上,负责发送adb命令daemon守护进程,在手机上,负责接收和执行adb龠令server端, 在电脑上,负责管理client和d测试

Appium构成和工作原理

前言:每一篇博客我都想写一个前言,第一是明确我对写这篇博客得态度,必须要认真和用心,另外作为技术分享,我也希望能帮助到一些伙伴有一些技术性得提升,测试 “点点点” 得时代已经结束,毕竟现在是智能化、自动化的时代,我们也必须要用技术武装自己,这样才能不被时代抛弃(明明可以靠脸吃饭的我,硬是吃成了一个胖子),那么下面我们言归正传,介绍一下Appium的基本使用,以前有些同事想搞这个但是止步于配置,你呢?

安装java环境和ANDROID-SDK

jdk和android-sdk文件下载地址:

链接:https://pan.baidu.com/s/1PEIfAbVwTR5mdL-6Ohca2g 
提取码:3bmu 

安装步骤:
  1. 下载后安装JAVA
  2. 配置JAVA环境变量
添加 JAVA_HOM  变量
       变量值为JDK在你电脑上的安装路径例如:
       C:\Program Files\Java\jdk1.8.0
       创建好后则可以利用%JAVA_HOME%作为JDK安装目录的统一引用路径。
打开 PATH 后设置 bin目录
       %JAVA_HOM%\bin
  1. 安装 android-sdk 并设置环境变量
添加 ANDROID_SDK  变量
       变量值为JDK在你电脑上的安装路径例如:
       C:\Program Files\android\android-sdk-windows
       创建好后则可以利用%JAVA_HOME%作为JDK安装目录的统一引用路径。
打开 PATH 后设置 bin目录
       %ANDROID_SDK%\platform-tools
       %ANDROID_SDK%\tools
  1. 检查是否安装成功,打开cmd,分别输入java -version,adb 不报错则配置正确

  2. adb构成

    • client端, 在电脑上,负责发送adb命令
    • daemon守护进程,在手机上,负责接收和执行adb龠令
    • server端, 在电脑上,负责管理client和daemon之间的通信
  3. adb工作原理

    • client遥将命令发送给server端
    • server端会将命令发送给daemon端
    • daemon端进行执行
    • 将执行结果,返回给server端
    • server端将结果再返回给client端

安装Appium(配合夜游模拟器使用)

  1. 安装python环境
  2. 下载并安装appium客户端和夜游模拟器(下载后分别双击安装即可)
 链接:https://pan.baidu.com/s/1tGlQLZbwCSCTYptgetYRwg 
 提取码:5dpf 

  1. Appium-python 库安装

     pip install Appium-Python-Client
    
  2. appium和夜游模拟器的连接

    1. 开启appium

    2. 打开夜神模拟器开发者模式

      4.2.1 打开夜神模拟器,打开设置,调成手机模式,初次进入的话,进入设置,
      点击版本号5次,可以激活使用开发者模式,进入后打开USB调试功能
      4.2.2 打开电脑文件资源管理器,进入夜神模拟器的安装位置,在地址栏输入cmd,
      回车,会打开cmd窗口,进入的路径就是夜神模拟器的安装位置。我的默认安装位置:		 C:\Program Files\Nox\bin
      4.2.3 然后命令行窗口中输入nox_adb.exe connect 127.0.0.1:62001 即可以连接到adb
      4.2.4 完成上述步骤后,此时启动appium便可以开始执行测试脚本了
      

adb 常用命令

获取设置程序的 包名 和 界面名

1.包名:决定程序的唯一性
2.界面名:程序中的每一个界面,对应一个界面名称

  • windows:
adb shell dumpsys window windows | findstr mFocusedApp
  • mac | Linux
adb shell dumpsys window windows | grep mFocusedApp


这里关于adb命令不做过多说明,个人经验多记就好,不是难点。

Appium使用(配合夜游模拟器使用)

Appium启动过程介绍

  1. appiun的启动实际上是在本机使用了4723端口开启了一个服务
    我们写的python代码会访问本机的appium服务器,并获取driver对象
  2. appium会将我们的driver对象调用的方法转化成post请求,提交给appium服务器
  3. appium 通过接收到的post请求发送给手机,再由手机进行执行

Appium的基础操作API(基本目标)

  1. 能够使用appium在脚本内启动其他app
# 启动短信的应用程序(跳转其他应用)
# app_package:要跳转的应用程序名
# app_activity:要跳转的页面名
driver.start_activity("com.android.contacts",".activities.PeopleActivity")
  1. 能够使用appium获取包名和界面名
#获取当前的程序的包名和界面名
page_name = driver.current_package
activity_name = driver.current_activity
print(page_name,activity_name)
  1. 能够使用appium关闭app和驱动对象(可以通过如下代码对比)

driver.quit():直接关闭驱动对象,退出会话
driver.close_app():退出当前App回到主界面

#退出当前App回到主界面(com.vphone.launcher)
driver.close_app()
print(driver.current_package)

time.sleep(4)

#直接关闭驱动对象
driver.quit()
print(driver) #driver对象存在,
print(driver.current_package) #当执行到这行代码时,异常(A session is either terminated or not started)
  1. 能够使用appium安装和卸载app

driver.is_app_installed(): 判断是否安装了程序
driver.remove_app():卸载安装程序
driver.install_app():安装本地程序包

isinstall = driver.is_app_installed("com.ss.android.ugc.aweme")
if (isinstall):
    print("程序已安装,卸载程序")
    driver.remove_app("com.ss.android.ugc.aweme")
else:
    print("程序未安装,安装程序")
    driver.install_app(
        "C:/Users/Administrator/Desktop/Downloads/aweme_aweGW_v11.2.0_97887f5.apk"
        )
  1. 能够使用appium将应用置于后台

driver.background_app()

#该方法往往用来测试程序的热启动,进入后台后,等待一段时间,自动回到前台
#seconds:单位秒
driver.background_app(10)

从页面中获取元素信息(UIAutomatorViewer)

主要作用:定位元素的时候必须根据元素的相关特征来进行定位,而我们的UlutomnatorVewer就是用来获取元素特征的,概括来说就是用来扫描和分析
Android应用程序的uI控件的工具。
使用步骤:

  • step1:打开UIAutomatorViewer

    • windows:在自己安装的android-sdk-windows的tools目录下打开uiautomatorviewer.bat
    • mac: 同样在android-sdk-windows的tools/bin目录下打开uiautomatorviewer
  • step2:打开待测试app要获取元素的页面(真机或者模拟器)

  • step3:使用uiautomatorviewer获取元素(抖音为例)

元素定位操作API(常用操作)

要求:熟悉HTML,CSS
能够分别使用id、class、 xpath定位某一个元素
能够分别使用id、class、 xpath定位某-组元素

提示:所定位的元素,只能是基于界面内的可见元素

定位一个或者一组元素
  • 根据id定位元素

driver.find_element_by_id()
driver.find_elements_by_id()

  • 根据class定位元素

driver.find_element_by_class_name()
driver.find_elements_by_class_name()

  • 根据class定位元素

driver.find_element_by_xpath("//[@content-desc=’ ']")
driver.find_elements_by_xpath("//
[@content-desc=’ ']")

注意:

  1. find_element_by_xxx 如果出现了多个id、class相同的元素,以上方法只会定位到第一个,find_elements_by_xxx 会定位一组

元素等待

工作场景: 由于一些原因,我们想找的元素并没有立刻出来,此时如果直接定位可能合报销,比如以下原因

  1. 由于网络速度原因
  2. 服务器处理请求原因
  3. 电脑配置原因
  • 隐式等待

    1. 说明:等待元素加载指定的时长,超出时长抛出NoSuchElementException异常

    2. 使用:在获取driver对象后,使用driver调用implcity _wait方法即可

      # 在设置了超时时间之后,后续所有的定位元素的方法都会在这个时间内等待元素的出现。
      # 如果在设定时间出现了,直接进行后续操作。
      # 如果在设定时间没有出现,则报错,NoSuchElementException
      
      driver.implicitly_wait(3)
      
  • 显示等待

    1. 说明:当定位元素的超时时间设置为不同的值的时候,等待元素加载指定的时长,超出时长抛出TimeoutException异常

    2. 使用:WebDriverWait(driver,超时时长,调用频率).until(lambda x:x.find_element_by_id(" "))

      # 在5秒内,每一秒钟找一次id为:"com.ss.android.ugc.aweme:id/c3k" 得元素
      # 如果在设定时间出现了,直接进行后续操作。
      # 如果在设定时间没有出现,则报错,NoSuchElementException
      # 只针对于当前寻找元素有效
      
      button = WebDriverWait(driver,5,1).until(lambda x:x.find_element_by_id("com.ss.android.ugc.aweme:id/c3k"))
      button.click()
      

经验总结: 因为显示和隐式等待得作用域不同,需要分具体情况来使用,如果要单独设置某一个元素得等待时间则使用显示等待,如果要设置所有元素得等待时间,则使用隐式等待,不推荐使用time.sleep()这种强制等待得方式

元素操作API

1.使用代码点击按钮(前提定位到该元素,并且该元素可点击)

element.click() # element:为定位的元素

2.使用代码对输入框输入文字(前提定位到该元素,并且该元素是文本框)

element.send_keys(value) # value:为输入文本的内容 ;element:为定位的元素

3.使用代码对输入框清空文字 (前提定位到该元素)

element.clear() # element:为定位的元素

4.使用代码获取元素的文本内容(返回数据类型为String)

element.text #element:为定位的元素

5.能够使用代码获取元素的位置和大小(返回数据类型为dict)

element.location # element:为定位的元素
element.size # element:为定位的元素

6.能够使用代码根据属性名获政元素的属性值

根据特征定位到元素后,使元素的属性名获取对应的属性值
使用get_attribute可以获取这些元素的enabled、text、content-desc、
resource-id、class 等的属性值
注意:
。想要获取resource id使用resourceId属性名API >= 18
。想要获取class使用ClassName属性名API >= 18
。想要获取content-desc使用 name 属性名
。其他的属性,都可以参考uiautomator viewer中的属性名

element.get_attribute(“enabled”)
element.get_attribute(“text”)
element.get_attribute(“name”)
element.get_attribute(“resourceId”)
element.get_attribute(“ClassName”)

页面的滑动和拖拽事件

工作场景:

自动化测试的时候,有些按钮是需要滑动几次屏幕后才会出现,
此时,需要模拟手指的滑动,这里就用到了滑动和拖拽事件
  1. 使用swpe滑动屏幕
  2. 使用scroll滑动屏幕
  3. 使用drag_and_drop滑动屏幕

swpe滑动屏幕

说明:从一个坐标位置滑动到另一个坐标位置,只能是两个点之间的滑动。

driver.swipe(start_x,start_y,end_x,end_y,duration)

"""
Args:
    start_x:(起始位置x坐标) x-coordinate at which to start
    start_y:(起始位置Y坐标)  y-coordinate at which to start
    end_x:(结束位置x坐标) x-coordinate at which to stop
    end_y:(结束位置y坐标) y-coordinate at which to stop
    duration: (滑动持续的时间,单位毫秒)time to take the swipe, in ms.

Usage:
    driver.swipe(100, 100, 100, 400)
"""
driver.swipe(100,50,100,2000,3000)

注意:

  • 使用该方法如果start_y和end_y的y坐标差值太大,会出现偏差(因为惯性),如果坐标差值太大建议使用duration参数缓冲(持续时间越长,惯性越弱)。
  • 当 start_y 小于 end_y 表示向上拉
  • 当 start_y 大于 end_y 表示向下拉
scroll滑动屏幕
说明:从一个元素滑动到另一个元素,直到页面自动停止。

driver.scroll(origin_el,destination_el,duration)

"""
Args:
    origin_el: 滑动的起始元素
    destination_el: 滑动的结束元素
    duration: 持续时间单位秒,default:600ms
Usage:
    driver.scroll(el1, el2)
"""

driver.scroll(start_element,end_element)
drag_and_drop滑动屏幕
说明:从一个元素滑动到另一个元素,第二个元素替代第一个元素原本屏幕上的位置

driver.drag_and_drop(origin_el,origin_el)

"""
Args:
    origin_el: 起始元素
    destination_el: 目标元素
"""
driver.drag_and_drop(origin_el,origin_el)

TouchAction常用手势操作

工作应用场景: 
TouchAction可以实现一些针对手势的操作,比如滑动。长按、拖动等等。
工作中可能需要一些复杂的手势,就可以将这些基本手势组合成一个相对复杂的手势。
  1. 使用代码完成轻敲手势
  2. 使用代码完成按下手势
  3. 使用代码完成抬起手势
  4. 使用代码完成等待操作
  5. 使用代码完成长按手势
  6. 使用代码完成手指移动操作
使用流程
  1. 创建TouchAction时象
  2. 通过对象调用想执行的手势
  3. 通过perform)执行动作
使用代码完成轻敲手势
  • 说明:模拟手指对某个元素或坐标****按下并快速抬起。比如,固定点击(150, 200)的位置。

TouchAction(driver).tap( element , x , y ).perform()

"""
element: 要轻敲的元素
x : 相对于元素的左上角,x坐标点击
y : y坐标。如果使用y,也必须设置x。
"""
# 根据元素完成轻敲
tap_element = driver.find_element_by_id("")
TouchAction(driver).tap(element=tap_element).perform()

# 根据坐标完成轻敲,敲击位置(70,100)
TouchAction(driver).tap(x=70,y=100).perform()

注意:如果你认真听,会发现,敲击的过程会发出 “咚” 的声音。

使用代码完成按下、长按、等待、抬起手势

说明:模拟手指- 直按下,模拟手指抬起。可以用来组合成轻敲或长按的操作

TouchAction(driver).press().perform()
TouchAction(driver).release().perform()
TouchAction(driver).long_press().perform()
TouchAction(driver).press().wait().release().perform() #等价于第三种方式

press_element = driver.find_element_by_id("com.ss.android.ugc.aweme:id/emz")
# 按下或者抬起
"""
el: the element to press
x: x coordiate to press. If y is used, x must also be set
y: y coordiate to press. If x is used, y must also be set
pressure: 仅仅iOS端使用
"""
#根据元素长按
TouchAction(driver).press(el=press_element).perform()
#根据坐标长按
TouchAction(driver).press(x=70,y=100).perform()

"""
el: the element to press(要按的元素对象)
x: x坐标,x存在,则y必须存在
y: y坐标,y存在,则x必须存在
duration: 长按持续时间(毫秒)
"""
#根据元素长按,并抬起
TouchAction(driver).press(el=press_element).release().perform()

#根据元素长按持续时间为1秒,并抬起
TouchAction(driver).long_press(el=press_element,duration=1000).release().perform()

#按下等待一秒然后抬起
"""
wait method
    Args:
        ms: 暂停,持续时间
"""
TouchAction(driver).press(el=press_element).wait(1000).release().perform()
使用代码完成手指移动操作

使用场景:在开发过程种有些功能是用户私有的,可以根据用户习惯设置密码(手势密码)
说明:模拟手指移动操作,比如,手势解锁需要先按下,再移动。

TouchAction(driver).press(x=146,y=523).move_to(x=449,y=523).perform() #按下位置146,523,移动到449,523

"""
Move the pointer from the previous point to the element or point specified
从一个点移动到另一个点(或元素)
Args:
    el: 要移动到的元素(element)
    x: 要移动到的位置的x坐标,x存在,则y必须存在
    y: 要移动到的位置的y坐标,y存在,则x必须存在
"""
TouchAction(driver).press(x=146,y=523).move_to(x=449,y=523).move_to(x=750,y=523).move_to(x=447,y=822).move_to(x=150,y=1125).move_to(x=445,y=1125).move_to(x=750,y=1125).release().perform()

其他(手机操作API)

  1. 获取手机分所率
driver.get_window_size()

打印结果如下:
{'width': 900, 'height': 1600}
  1. 获取手机截屏
driver.get_screenshot_as_file("设置为要保存的文件路径")
  1. 获取和设置网络状态
    应用场景: 现在一般的手机应用在使用流量看视频的时候,大部分都会提示用户正在是否继续播放。作为测试,我们可能需要用自动化的形式来判断是否有对应的提示。即用流量的时候应该有提示,不用流量的时候应该没有提示(一般情况下)。

    3.1 获取当前网络状态

    driver.network_connection
    

    注意:返回值为int类型的数字个数字含义如下(0表示关闭,1表示开启

    3.2 设置手机网络状态

    """
    Args:
       connection_type: int 类型 appium.webdriver.ConnectionType 的枚举类型
    
    class ConnectionType:
       NO_CONNECTION = 0
       AIRPLANE_MODE = 1
       WIFI_ONLY = 2
       DATA_ONLY = 4
       ALL_NETWORK_ON = 6
    
    """
    # 例如设置当前网络类型为AIRPLANE_MODE 
    result = driver.set_network_connection(1)
    

    3.3 判断当前手机网络状态

    from appium.webdriver.connectiontype import ConnectionType
    if driver.network_connection == ConnectionType.WIFI_ONLY:
        print("WIFI_ONLY,只开启了WIFI")
    elif driver.network_connection == ConnectionType.NO_CONNECTION:
        print("没有网络")
    elif driver.network_connection == ConnectionType.NO_CONNECTION:
        print("飞行模式")
    elif driver.network_connection == ConnectionType.DATA_ONLY:
        print("使用流量")
    else:
        print("流量和WIFI均已开启")
    
  2. home键或者说是返回键(发送键到设备)
    说明:模拟按“返回键" 、home键等等操作,例如很多应用有按两次返回键退出应用的功能,这个功能需要我们做
    自动化就需要使用该功能

    """
    Args:
        keycode: the keycode to be sent to the device
        metastate: meta information about the keycode 
        being sent
    """
    #音量+
    driver.press_keycode(keycode=24)
    #返回
    driver.press_keycode(keycode=4)
    

关于keycode:https://www.cnblogs.com/yc-c/p/9014771.html

  1. 能够打开和关闭手机通知栏

    driver.open_notifications()
    time.sleep(2)
    driver.press_keycode(4)
    time.sleep(1)
    

总结:最后无论这篇分享是否能帮到你,都希望路过的你能有哪怕零点一分的收获,我花费的时间也就没有浪费,最后献上通俗易懂的代码:

下载地址: https://github.com/ljhyigehaoren/Appium_demo.git

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服