浅谈Appium之AppUI自动化

一、Appium简介

Appium是一个开源测试自动化框架,可用于原生(native app),混合(html)和移动Web应用程序()测试。 它使用WebDriver协议驱动iOS,Android和Windows应用程序。

二、Appium优势

  • 可以跨平台同时支持android、ios
  • 支持多种语言,java、python、php、Ruby等
  • 不用为复杂的环境发愁
  • 有selenium经验,可直接上手

三、环境依赖

  • Appium-desktop -->二合一 node.js和 appium
  • Appium-Python-Client
  • Python
  • JDK
  • Andriod SDK

3.1、Android SDK 安装配置

下载地址: http://tools.android-studio.org/index.php/sdk
根据自己的PC平台下载对应版本即可
安装完成后需要配置环境变量:ANDROID_HOME 之前adb操作的时候已经配置过,把下面的再添加进去就可以
浅谈Appium之AppUI自动化
浅谈Appium之AppUI自动化

四、Appium Desktop

Appium Desktop是一款适用于Mac,Windows和Linux的开源应用程序,它以美观而灵活的用户界面为您提供Appium自动化服务器的强大功能。 它是几个Appium相关工具的组合:

  • Appium Server的图形界面。 可以设置选项,启动/停止服务器,查看日志等…也不需要使用Node 的NPM来安装Appium,因为Node运行时与Appium Desktop捆绑在一起。
  • 可以使用Inspector查看应用程序的元素,获取有关它们的基本信息,并与它们进行基本的交互。
    【注】:Appium Desktop与Appium不同。 Appium Desktop是Appium的图形前端,带有其他工具。 Appium Desktop以其自己的节奏发布,并拥有自己的版本控制系统。 就像国内很多定制的Android系统有自己版本号,但是都是基于一个Android系统版本封装的。版本号不一定与Andriod原生系统版本号一致。
    如:魅族的flyme6.0系统的内核是Android 5.1

4.1、安装Appium-desktop

下载地址:https://github.com/appium/appium-desktop/releases
Appium-desktop工具其实也封装了Appium server和Node.js依赖环境以及获取元素的图形化工具,本身是一个单独的工具;Appium-desktop主界面包含三个菜单Simple,Advanced、Presets

4.1.1、Simple

4.1.1.1、host

设置Appium server的ip地址,本地调试可以将ip地址修改为127.0.0.1

4.1.1.2、port

设置端口号,默认是4723不用修改

4.1.1.3、start server

启动appium server
浅谈Appium之AppUI自动化

4.1.2、Advanced

高级参数配置修改,主要是一些Android和iOS设备,log路径等相关信息的配置
浅谈Appium之AppUI自动化

4.1.3、persets

将Advanced中的一些配置信息作为预设配置
浅谈Appium之AppUI自动化

五、Capability

5.1、什么是Capability

  • desired capability的功能是配置Appium会话。他们告诉Appium服务器您想要自动化的平台(版本)和应用程序。
  • Desired Capabilities是一组设置的键值对的集合,其中键对应设置的名称,而值对应设置的值。(如:“platformName”: “Android”)Desired Capabilities主要用于通知Appium服务器建立需要的Session。

5.2、session

Appium的客户端和服务端之间进行通信都必须在一个Session的上下文中进行。客户端在发起通信的时候首先会发送一个叫作“Desired Capabilities”的JSON对象给服务器。服务器收到该数据后,会创建一个session并将session的ID返回到客户端。之后客户端可以用该session的ID发送后续的命令。

5.3、常用Capability配置

Capability官方完整文档
如果有了解过Capability的人会发现一个问题,其实他主要分成了三部分:公共部分、ios部分、android部分,如果android想用ios的那是不可能的,so,老老实实去了解每个平台有哪些,他们的作用是什么
浅谈Appium之AppUI自动化
浅谈Appium之AppUI自动化
浅谈Appium之AppUI自动化

5.4、Capability启动App演示

5.4.1、New Session Window 会话建立

  • Automatic Server 本地AppiumServer服务
  • Custom Server:例如,如果要针对运行在网络中另一台计算机上的Appium服务器启动Inspector会话,这很有用。
  • Sauce Labs:如果您无法访问机器上的iOS模拟器,则可以利用Sauce Labs帐户在云中启动Appium会话。
  • TestObject:您还可以利用TestObject的真实设备云来进行真机测试。
  • headspin:使用远程设备来创建会话。

5.4.2、desired capability参数Json

使用adb shell dumpsys window | findstr mCurrentFocus 命令查看当前运行的包名和Activity更清晰一些
adb shell dumpsys activity activities >C:\Users\xxx\Desktop\aa.txt
查看activty等信息:appt dump badging E:\xxx.apk
查找初始加载页面: appt dump badging E:\xxx.apk | findstr “lauchable-activity”
浅谈Appium之AppUI自动化

5.4.3、常见问题

——那些踩过的坑

[MJSONWP] Encountered internal error running command: Error: Error occured while starting App. Original error: Permission to start activity denied.

activity在清单文件里面没添加android:exported=”true”的话,不能直接打开对应的activity,需要从启动页activity打开。 exported属性就是设置是否允许activity被其它程序调用
新的会话窗口允许您构造一组desired capabilities,用于启动Appium会话。您可以针对当前运行的Appium Desktop服务器(默认的)启动一个会话,或者您可以针对各种其他端点启动一个会话。
因为不需要使用Appium Desktop自己的服务器,您可以在不启动Appium Desktop服务器的情况下进入新的会话窗口。只需点击“File”(Windows / Linux)或“Appium”(Mac),然后选择“New Session…”,它将打开新的会话窗口,而不必启动本地服务器。在这种情况下,将禁用附加到本地服务器。

六、案例——考研帮kaoyan3.1.0.apk

6.1、运行前检查事项

1.检查设备是否连接
2.检查Appium server是否启动
3.检查Capability配置信息是否正确

6.2、Appium Settings、Unlock

1.首次启动Appium会在设备上安装2个守护app,Appium Settings和Unlock 部分设备系统由于权限的问题(如:三星S6 edge+)需要用户手动确认安装,否则不安装守护App会导致脚本运行失败,安装好后不要随意卸载这两个App。

  • Unlock :用于解锁手机弹窗提示
  • Appium Setting:Appium守护app
    2.from appium import webdriver 中的webdriber模块和selenium中的webdriver模块不一样!
{python安装路径}}\Lib\site-packages\appium\webdriver #webdriver模块源码路径

6.3、Appium报错&解决方案

——那些年我们踩过的坑

6.3.1、Appium服务未启动

urllib.error.URLError: <urlopen error [WinError 10061] 由于目标计算机积极拒绝,无法连接。

【解决方案】点击启动Appium按钮后,出现[Appium] Welcome to Appium v1.7.2提示后再运行脚本

6.3.2、会话冲突

error: Failed to start an Appium session, err was: Error: Requested a new session but one was in progress

【报错分析】 之前的会话没有关闭,然后又运行了测试实例,也没有设置覆盖.
【解决方案】 重新停止appium服务,开启Appium服务 在AdVance界面勾选Allow Session Override选项 ,重启Appium 测试结束在AfterClass加driver.quit()

6.3.3、未安装java环境

selenium.common.exceptions.WebDriverException: Message: A new session could not be created. (Original error: 'java -version' failed. Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "java -version"

6.3.4、设备未连接

selenium.common.exceptions.WebDriverException: Message: An unknown server-side error occurred while processing the command. Original error: Could not find a connected Android device.

【解决方案】由于设备未连接,或者连接后未开启USB Debug。需要重新连接设备即可。

6.3.5、更换手机设备后如下对应的属性要记得更新,否则无法正常运行脚本。

desired_caps['platformVersion'] = 'XXX'
desired_caps['deviceName'] = 'Galaxy S6 edge+'

6.3.6、launchable activity 值写错

Activity used to start app doesn't exist or cannot be launched! Make sure it exists and is a launchable activity

【解决方案】

  • launchable activity 写错更正即可。
  • 如果是存在此activity,则一定是AndroidMainfest.xml.xml中,当前activity设置的属性exported=false,表示当前activity无法被外部程序唤醒。(appium无法唤醒此类)需要研发人员去修改参数。

6.3.7、系统权限问题

Failure [INSTALL_FAILED_USER_RESTRICTED])

【解决方案】
1.USB安装管理权限限制,关闭即可。
2.开启安装允许未知来源app选项

6.3.8、服务异常

An unknown server-side error occurred while processing the command” while opening the App

【解决方案】重新启动Appium服务

6.4、元素定位

与Web自动化测试一样,app自动化测试过程中最重要一个环节就是元素定位,只有准确定位到了元素才能进行相关元素的操作,如输入、点击、拖拽、滑动等。appium提供了许多元素定位的方法,如id定位、name定位、class定位、层级定位等等… 接下来将会给大家来实践运用这些定位技巧。

6.4.1、id

日常生活中身边可能存在相同名字的人,但是每个人的身份证号码是唯一的,在app界面元素中也可以使用id值来区分不同的元素,然后进行定位操作。Appium中可以使用 find_element_by_id() 方法来进行id定位。

# 使用uiautomatorviewer查看 或者appium inspector查看
driver.find_element_by_id('android:id/button2')
driver.find_element_by_id('com.tal.kaoyan:id/tv_skip')

6.4.1.1、思考

  • 如果安装的版本最新的包,或者升级到了最新的版本,则启动后没有升级弹窗元素该如何处理?
  • 跳过引导页面首次启动和非首次启动场景该如何处理?

6.4.1.2、异常捕捉

if语句判断无法生效(因为找不到元素会报错),但是我们发现一个突破口,那就是捕捉NoSuchElementException异常。

from  appium import webdriver
from selenium.common.exceptions import NoSuchElementException

desired_caps={}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '6.0'
desired_caps['deviceName'] = 'BTF4C17216005082'


desired_caps['app']='E:\kaoyan3.1.0.apk'
desired_caps['appPackage']='com.tal.kaoyan'
desired_caps['appActivity']='com.tal.kaoyan.ui.activity.SplashActivity'

desired_caps['noReset']='True'

driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_caps)
driver.implicitly_wait(5)


def check_cancelBtn():
    print("check_cancelBtn")

    try:
        cancelBtn = driver.find_element_by_id('android:id/button2')
    except NoSuchElementException:
        print('no CancelBtn')
    else:
        cancelBtn.click()


def check_skipBtn():
    print("check_skipBtn")
    try:
        skipBtn = driver.find_element_by_id('com.tal.kaoyan:id/tv_skip')
    except NoSuchElementException:
        print('no skipBtn')
    else:
        skipBtn.click()

check_cancelBtn()
check_skipBtn()

注:

  • send_keys()传入中文时需要在capability中配置如下内容:
desired_caps['unicodeKeyboard']="True"
desired_caps['resetKeyboard']="True"

设置之后会有Appium的输入法守护来执行输入操作

  • 使用Appium做了输入操作之后,如果出现输入法无法唤起,可以在系统设置——语言和输入法——将当前输入法替换为系统输入法或者其他输入法。

6.4.2、name

根据name进行定位,对于android来说,就是text属性

from find_element.capability import *
driver.find_element_by_name('请输入用户名')
driver.find_element_by_name('登录')

说明:由于text稳定性不是很好,所以appium 1.5开始废弃了该方法。

6.4.3、class

classname定位是根据元素类型来进行定位,但是实际情况中很多元素的classname都是相同的,
如上例中登录页面中的用户名和密码都是className属性值都是:“android.widget.EditText” 因此只能定位第一个元素也就是用户名,而密码输入框就需要使用其他方式来定位,这样其实很鸡肋.一般情况下如果有id就不必使用classname定位。

by_classname.py
from find_element.capability import driver

driver.find_element_by_class_name('android.widget.EditText').send_keys('付腾飞')
driver.find_element_by_class_name('android.widget.EditText').send_keys('1234')
driver.find_element_by_class_name('android.widget.Button').click()

6.4.4、相对定位

相对定位是先找到该元素的有对应属性的父元素节点,然后基于父元素进行元素定位。
测试案例
不使用id元素定位方式,在新用户注册界面点击添加头像按钮。

from find_element.capability import driver

driver.find_element_by_id('com.tal.kaoyan:id/login_register_text').click()

root_element=driver.find_element_by_id('com.tal.kaoyan:id/activity_register_parentlayout')
root_element.find_element_by_class_name('android.widget.ImageView').click()

6.4.5、xpath

xpath定位是一种路径定位方式,主要是依赖于元素绝对路径或者相关属性来定位,但是绝对路径xpath执行效率比较低(特别是元素路径比较深的时候),一般使用比较少。通常使用xpath相对路径和属性定位。

表达式 描述
/ 从根节点选取
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
nodename 选取此节点的所有子节点
. 选取当前节点
选取当前节点的父节点
@ 选取属性
通配符 描述
* 匹配任何元素节点
@* 匹配任何属性节点
node() 匹配任何类型的节点
from find_element.capability import driver

driver.find_element_by_xpath('//android.widget.EditText[@text="请输入用户名"]').send_keys('ftf1234')
driver.find_element_by_xpath('//*[@class="android.widget.EditText" and @index="3"]').send_keys('ftf123456')
driver.find_element_by_xpath('//android.widget.Button').click()
# driver.find_element_by_xpath('//*[@class="android.widget.Button"]').click()

扩展资料:xpath语法

6.4.6、UIAutomator定位

UIAutomator元素定位是 Android 系统原生支持的定位方式,虽然与 xpath 类似,但比它更加好用,且支持元素全部属性定位.定位原理是通过android 自带的android uiautomator的类库去查找元素。 Appium元素定位方法其实也是基于Uiautomator来进行封装的。
使用方法 find_element_by_android_uiautomator() 可以运用UiAutomator元素定位。

6.4.6.1、id定位

id定位是根据元素的resource-id属性来进行定位,使用 UiSelector().resourceId()方法即可。

from find_element.capability import driver

driver.find_element_by_android_uiautomator\
    ('new UiSelector().resourceId("com.tal.kaoyan:id/login_email_edittext")').send_keys('ftf1234')

driver.find_element_by_android_uiautomator\
    ('new UiSelector().resourceId("com.tal.kaoyan:id/login_password_edittext")').send_keys('ftf123456')

driver.find_element_by_android_uiautomator\
    ('new UiSelector().resourceId("com.tal.kaoyan:id/login_login_btn")').click()

6.4.6.2、text定位

text定位就是根据元素的text属性值来进行定位,new UiSelector()

driver.find_element_by_android_uiautomator\('new UiSelector().text("请输入用户名")').send_keys('ftf1234')

6.4.6.3、class name定位

与Appium class定位方式一样,也是根据元素的class属性来进行定位。

driver.find_element_by_android_uiautomator\('new UiSelector().className("android.widget.EditText")').send_keys('zxw1234')
上一篇:Appium Android 获取包名和 Activity 的几种方法 (转)


下一篇:⾃动化测试环境搭建