Appium Android 自动化测试入门

果汁 · 2017年09月10日 · 最后由 小辣 回复于 2017年09月12日 · 1729 次阅读
本帖已被设为精华帖!

一、selenium、WebDriver 了解

经常听说 selenium、WebDriver 了,但他们是什么,用来干什么的呢?今天借此课程查阅一些资料,原来是这样子的。

1.1 进一步了解 WebDriver

  • WebDriver 提供了一个设计良好的面向对象的 API,完全就是一套类库,独立的,不依赖于任何测试框架。Appium 就是直接继承了 WebDriver 的 Client 端,进行脚本编写和指令发送;
  • WebDriver 是如何驱动浏览器的呢?WebDriver 它直接调用每个浏览器内置的自动化支持。

1.2 WebDriver API

官方API:http://www.seleniumhq.org/docs/03_webdriver.jsp#introducing-the-selenium-webdriver-api-by-example
中文API:https://wenku.baidu.com/view/6c03a2235acfa1c7aa00ccaf.html
关于 Webdriver API 的学习以及使用方法:

  • API 只是一些儿封装的方法,大致浏览一下,知道有哪些 API,完成什么操作即可,没有必要花很多时间去学习,边用边学。
  • API 的学习要灵活,最好把同类的操作放到一起比较一下。因为在编写测试用例的过程中,不仅仅只有一种方法可以达到预期的结果。
  • 要会使用Intellij等编辑器的联想功能。在写测试用例的时候,如果一时想不起来用什么方法了,可以利用联想功能进行查询。

WebElement 对象提供了多种定位元素策略:可通过 ID、Name、ClassName、TagName、LinkText、Xpath 等定位元素。

参考文章:http://blog.sina.com.cn/s/blog_68f262210102vlie.html

1.3 Driver是什么?

经常说 WebDriver、 RemoteWebDriver、AppiumDriver、AndroidDriver,那什么是 Driver ,它是用来做什么的呢?

  • Driver 其实就是 Appium server 跟手机之间建立的 session 的一个实例
  • 通过 Driver 封装好的 API 发送相关指令达到自动化。

各个Driver之间的继承(区别):http://discuss.appium.io/t/what-is-the-use-or-difference-between-androiddriver-iosdriver-appiumdriver-and-remote-webdriver/8750

二、APP UI 自动化

2.1 APP UI 自动化的实质

  1. 发送指令,取得元素;
  2. 计算元素坐标;
  3. 根据指令具体内容,自动化驱动程序进行操作。

2.2 各个自动化框架之间的区别

我们知道了APP UI自动化的实质,所以现在流行的几个自动化工具做UI自动化的实质都一样,都是上面的3个步骤。它们的区别是:

  1. 怎么发送指令?谁来把这个指令告诉手机?
  2. 手机用什么驱动自动化点击等操作(即自动化驱动程序是什么)?

2.3 常见 UI 自动化测试框架

下面详细看看 Appium 原理。

三、Appium 原理

  • Appium 并不是一个自动化驱动程序
  • 核心在于它是一个 server
  • 调度其他自动化驱动框架执行

自动化驱动框架有

  • Android:UIAUTOMATOR 2、UIAUTOMATOR、INSTRUMENTATION;
  • iOS:UIAUTOMATAION、XCUITESTING(WebDriverAgent)。 由于上面手机自动化驱动框架是由 Google (或 Apple)官方提供的,是跟 Android SDK 捆绑发布的,所以每次 Android 新的系统(SDK 升级)发布的时候,与 SDK 捆绑的自动化框架也会有升级(要么是对原有框架的优化如 Android 的 UIAUTOMATION 框架, 要么就是推出新的框架如 iOS废弃 UIAUTOMATION 框架 推出 XCUITESTING)。

我们再回顾各个自动化测试框架之间的区别

  1. 怎么发送指令?谁来把这个指令告诉手机?
  2. 手机用什么驱动自动化点击等操作(即自动化驱动程序是什么)?

那么 Appium 是如何实现的呢?

3.1 Appium原理——android架构图

  1. 怎么发送指令?谁来把指令告诉手机?
    Appium Client 端 脚本执行的时候,Client 端把每一行代码发送到 Appium server 端,Appium server负责接收脚本发送过来的内容,把脚本发送过来的内容进行翻译,翻译成一个统一的指令

    • 不论你用什么语言编写的脚本都会翻译成统一的命令,所以appium支持多语言;
    • 为什么能支持多语言呢,是因为 Appium 继承了selenium/WebDriver 的 client 的类;
    • 虽然支持不同的语言,但你只要学习不同语言的API,只需要看不同语言的脚本文档。
  2. 我们知道 Appium 不是一个自动化驱动程序,不去操作手机做自动化,那是谁来操作指令,指令又是怎么传到手机上的呢?
    Appium 提供了一个 bootstrap jar 包,Appium 会在运行的时候偷偷注入到手机上,Appium server 跟自己偷偷注入的这个 jar 包进行通信,jar 包拿到指令后,去调用手机的UIAUTOMATOR 去做执行

所以 Appium 是一个 server,起调度作用,把指令告诉手机里的 bootstrap.jar;真正执行自动化操作的是 Google 官方提供的自动化工具。

四、UIAUTOMATOR 框架

Android 的自动化框架 UIAutomator ,UIAutomator 框架提供了3个非常重要的类:

  1. 对系统硬件按钮、坐标等操作的 Device 类(对android系统硬件按钮、坐标等进行点击、滑动如 menu 键、home 键、拖动);
  2. 定位元素控件的 UIObject 类;
  3. 进阶操作的 UIScrollable 类。

五、Client 端脚本编写

5.1 用例的组成

以 Python 为类

  1. 申明测试类,如 Class SimpleAndroidTests(unittest.TestCase),(继承 unittest 的 TestCase 类) ;
  2. 这个类里主要有3种类型的方法:setUp()、tearDown()、test_xxx() (以test开头的方法,这就是测试用例,可以有多个); 当有多个测试方法时脚本执行顺序是:setUp -> method1 -> tearDown -> setUp -> method2 -> tearDown。下面详细看看这几个方法做了哪些事情?

5.2 setUp方法

首先我们看看 setUp 方法 写了什么?

def setUp(self):
desired_caps = {}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '6.0.1'
desired_caps['deviceName'] = 'Android Emulator'
desired_caps['app'] = PATH(
'../../../sample-code/apps/ApiDemos/bin/ApiDemos-debug.apk'
)

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

setUp方法先定义了 desired_caps,然后通过传入 desired_caps 实例化一个 self.driver,实例化过程做的事情有:
1.去 desired_caps 指定的手机机型系统删除原来手机里已有的 desired_caps 指定的APP;
2.再重新安装 desired_caps 指定的APP。

所以执行第2个测试用例时,登录态等会丢失(如果在第1个测试用例时登录了)。如果希望第2个测试用例不卸载重新安装,可以加一个参数配置:desired_caps['noRest']=true。但是这样又会有一个问题,下次执行第1个测试用例也不会卸载重装 APP 了。

desired_caps 设置的参数决定了 driver 启动时到底以什么状态来启动。那 desired_caps 设置的参数有哪些呢?可以在 Appium 的 GitHub 里查看:
输入 https://github.com/appium/appium,点击 docs 目录,点击 cn 目录,点击 writing-running-appium 目录,看到 caps.md 文件。

这里推荐另一个方法:python装饰器 @classmethod

在setUp和tearDown方法前写上装饰器@Classmethod,表示该方法针对这个类只执行一次,那么脚本执行顺序就变成了:setUp -> method1 -> method2 -> tearDown。这样第1个测试用例执行前就会卸载重新安装,直到这次所有测试用例执行完。这时可以把登录等操作放在 driver 实例化好且测试用例执行之前,如下代码所示:

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

3.self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps), 这行代码什么时候执行完毕呢?
在手机上 APP 启动且能看到页面,这行代码才算执行完毕,即 self.driver 实例成功,才会执行测试用例。

5.3 test_xxx方法(即测试用例)

  1. 有哪些 API 可以调用,查看API 文档
    如果不知道 Appium 提供了哪些可以 操作手机的 API ,可以查看 Appium 各个 Client 端 API 文档

    输入 https://github.com/appium/python_client,点击 appium 目录,点击 webdriver 目录,看到 webdriver.py 模块。
    这里是 Python Client 里面实例化的self.driver 所能调用的所有的 API(也是 webdriver 的源码)。

  2. 知道有哪些 API 了,那怎么定位元素呢?
    可借助 UIAutomatorviewer 工具进行元素定位(或者 Appium 的 inspect)。打开 UIAutomatorviewer 工具的方法是: 在命令行输入 uiautomatorviewer 即可启动。

    常用来定位元素的信息有:id、text、class、content_desc,他们对应的 API 是:by_id、by_text、by_class_name、by_accessibilityId,如果前三者都不能定位到元素,可以请开发帮忙把元素的 content_desc 信息加上,这样可以用 by_accessibilityId 定位元素。

  3. 提高脚本流畅度和稳定的2个方法 — 摒弃 time.sleep 线程等待方法
    确定页面有某个控件,但是脚本报错说找不到控件,这时候我们一般会在脚本里加 time.sleep 即线程等待。不建议用这种方法,更好的方法是:

    • 隐式等待implicitly_wait() 在 driver 生成的时候,设置隐式等待时间 self.driver.implicitly_wait(10),设置了之后,这个会在全局对所有 find_element_by_xxx 生效,如果某个控件没有马上找到,那么在10s以内循环的不停的去找这个控件直到找到,如果10s后仍然没有找到控件才会报错。
    • Webdriver wait 指定等待,直到某个控件出现才会做sth。
  4. 如何同时对多台设备执行自动化测试?
    启多个 Appium server 就可以。

    参数配置参考如下文档:输入 https://github.com/appium/appium,点击 docs 目录,点击 cn 目录, server-args 文件。

六、Hybrid 页面自动化测试

对Hybrid 页面进行自动化操作有两种方式: UIAutomator 以及 UIAutomator + ChromeDriver 。

6.1 通过 UIAutomator 框架

H5 页面是一个 WebView,UIAutomator 不支持操作 WebView 元素,一般情况下只认识 Android View(即 Native 页面)。
UIAutomator 会把 WebView 里所有元素转义成 Android View,但是大部分元素的 id、text 都为空,content_desc 内容 原 text 内容,所以这种情况下不能通过 id、text 信息来定位元素,可以使用 content_desc 信息定位元素。
但是这种方式并不是太通用,因为不同手机机型系统 UIAutomator 将 WebView 里元素转义元素的 content_desc 值不能保持一致的格式,如有的手机将某元素转义后的 content_desc 值为“登录”,有的手机却是 “u登录”等等。
这里 Google 提供了一种更好的方法,即第二种方法。

6.2 通过 UIAutomator + ChromeDriver 框架

在 Android 4.4 系统以后 Google 推出了 ChromeDriver,它跟 UIAutomator 是独立平行的,他是可以操作 WebView 的。
如果是 Hybrid 页面, bootstrap.jar 调起 ChromeDriver 完成自动化;如果是 Native 页面, bootstrap.jar 调起 UIAutomator 完成自动化。
所以 Appium 可以通过 bootstrap.jar 同时调起 UIAutomator 和 ChromeDriver 来完成 Hybrid 的自动化(只能针对 API > 4.3,是受 ChromeDriver 的限制)。

6.3 Hybrid 测试和 Native 测试有什么区别?

基本没什么区别,除了下面这一点。
前面提到:“如果是 Hybrid 页面, bootstrap.jar 调起 ChromeDriver 完成自动化,如果是 Native 页面, bootstrap.jar 调起 UIAutomator 完成自动化。”那么在脚本里如何实现呢?
通过切换上下文 Context

6.4 Hybrid 涉及的 API

  • 获取 APP 所有 Contexts
  • 获取当前 context
  • 切换 context

具体 API 可以查看 GitHub:https://github.com/appium/python-client/blob/master/appium/webdriver/webdriver.py

6.5 Chrome 框架如何获取 H5 页面元素

  1. 真机上 APP 的 WebView 的 debug 属性要打开。

    一般debug包默认是打开的,如果没有打开找开发协助,模拟器没有这个限制。

  2. Chrome 浏览器输入:chrome://inspect,点击页面上的 inspect 按钮

    需要访问 Google 源,所以需要翻墙!用右上角的定位工具(类似 chrome 网页定位元素)定位到元素,在右侧默认选择这块代码,右键选择:复制 - 复制 xpath。

  3. 不能翻墙又想精准定位元素的xpath

print(self.driver.page_source)

如果你没有翻墙可能在chrome上打不开上述页面,也可以采用下面的方法:输出h5页面的page_source,保存html文件,用chrome浏览器打开,右键选择 “ 检查 ”,再按照步骤 2 也可以获得元素的 xpath。最好能翻墙用步骤 2。

6.6 易踩的坑

  1. Native 与 WebView 之间的衔接

    一定要记得当前在哪个 Context 下

  2. WebView Context 请不要乱用手势操作

    由于在 WebView Context 下,自动化驱动框架是 ChromeDriver,而 flick、swipe(移动手机特有的操作)是 UIAutomator 框架支持的。 所以只能用 ChromeDriver 针对 web 端支持的手势 API 如 scroll 操作。

  3. 不要忘记 WindowHandle 的存在

    列表页有2个商户,假设商户详情页都是 WebView 页面,进入第1个商户详情页是一个 WebView,进入第2个商户详情页可能不是一个同一个 WebView,可能新起了一个 WebView。这个其实很正常,和 Chrome 浏览器类似,可以是在当前 tab 打开第2个商户页,也可能是新起一个 tab 打开商户页。
    如果明明切换了 Context 但是还是不能定位当前页面元素,有可能 Context 切换了,但是 WindowHandle 还留在上一个 WebView页面,需要对 WindowHandle 做一个切换。

七、其他——Linux 命令

  1. open . ,通过终端打开Finder
  2. tree -L 2 ,以树状图列出文件目录 2层
  3. subl 文件名 , 表示编辑文件(没有则新建文件)
  4. subl . ,使用sublime text 打开当前文件夹
  5. aapt dump badging 包名 ,得到包的相关信息
共收到 5 条回复 时间 点赞

这帖子质量不错啊!

笔记很全,用心了老铁

恒温 回复

都是老师授予的,向各位老师学习!😍

无言祖 回复

刚入门,还请多多指教😀

果汁 iOS 自动化测试 中提及了此贴 09月11日 21:40

棒,总结的很赞👍 👍 👍 👍 👍

思寒_seveniruby 将本帖设为了精华贴 12月18日 17:37
simple 专栏文章:[精华帖] 社区历年精华帖分类归总 中提及了此贴 12月13日 20:49
simple [精彩盘点] TesterHome 社区 2018年 度精华帖 中提及了此贴 01月07日 12:08
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册