Appium在Android UI测试中的应用实践

简介:

Android 测试工具与 Appium 简介

Appium 是一个 C/S 架构的,支持 Android/iOS Native, Hybrid 和 Mobile Web Apps 的测试框架,与测试程序通过 Selenum Webdriver 协议通讯。Webdriver 的好处是通过 HTTP RPC 的方式调用 Server 上的过程,编写测试脚本不受语言的限制,无论是 Python, Java, NodeJS 均可以方便的编写测试。本文中将使用 Python 进行编程。

起因是因为市场部的同事抛来如下需求:批量添加一些微信好友。直接抓取请求进行重放的方法是不靠谱的,微信与服务端的通讯均加密,Pass。考虑使用 xposed 等框架 hook 相关函数进行操作。但是 xposed 需要越狱,且开发复杂,Pass。后来想到了使用 UI 测试工具进行模拟操作,开发较为简单。

Android UI 测试工具有很多种,如 Monkey, UIAutomator, Selendroid, Robotium 等。其中 UIAutomator, Monkey, Selendroid 均为非侵入式的 UI 测试,也就是不需要修改源代码,只要安装了目标程序就可以进行测试。Robotium 需要与源码一同编译测试。Appium 实际上就是一个测试工具的统一调度软件,将不同的非侵入式测试工具整合在一起,对外提供统一的 API。在 Android 2.3 以前的版本,Appium 会调用 Selendroid ,之后的版本会直接使用 UIAutomator,iOS 下使用 UIAutomation。Appium 还支持 FirefoxOS 的 UI 测试。

安装 Appium

官网给出了命令行下的安装方法。但实际上 Appium 有 GUI 版本,更适合在 Windows/MacOS 下使用。Windows 下需要安装 .NET Framework。


  
  
  1. > brew install node      # get node.js 
  2. > npm install -g appium  # get appium 
  3. > npm install wd         # get appium client 
  4. > appium &               # start appium 
  5. > node your-appium-test.js 

Appium 需要依赖 Android SDK 编译在手机端运行的两个插件,因此需要首先安装相应的 Android SDK 版本。这里直接使用了 Android Studio 中自带的 SDK Manager。在 SDK Manager 中选择和测试机相对应的 SDK Platform 和较新的 Build-tools,如果需要使用模拟器测试还要装对应的 ARM/x86 System Image,以及 Intel HAXM Installer,用于加速 x86 虚拟机。Appium 使用 adb 来与目标机器通讯,因此对于真机和模拟器操作几乎都是相同的,如何建立模拟器在此不再赘述。

安装完成后需要在 Appium GUI 中配置 Android SDK 目录,随后选择 Android,点击 Launch 就可以启动 Appium Server。

Appium Server 默认会监听 http://localhost:4723 ,用于 RPC 通讯。下面我们就可以打开熟悉的编程环境,编写 UI 测试用例了。这里使用 Python 进行编写,需要先安装 Appium 的 Python Client ,然后再 python 中使用 appium.webclient 就可以连接 Appium server了。


  
  
  1. pip install Appium-Python-Client 

使用 Appium 进行 UI 控制

根据注释修改相应属性后即可运行测试。手机需要打开 ADB 调试,执行完以下代码后,Appium 会在手机上安装 Appium Settings 和 Unlock 两个程序,随后微信会被启动。


  
  
  1. from appium import webdriver 
  2.  
  3. desired_caps = {} 
  4.  
  5. desired_caps['platformName'] = 'Android' #测试平台 
  6.  
  7. desired_caps['platformVersion'] = '5.1' #平台版本 
  8.  
  9. desired_caps['deviceName'] = 'm3_note' #设备名称,多设备时需区分 
  10.  
  11. desired_caps['appPackage'] = 'com.tencent.mm' #app package名 
  12.  
  13. desired_caps['appActivity'] = '.ui.LauncherUI' #app默认Activity 
  14.  
  15. dr = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) #启动Remote RPC 

Selenum Webdriver 使用了一种类似于 JS 中的 DOM 模型的方法来选择页面中的元素。dr 为当前正在活动的 activity 对象,可以使用 findElementByXXX 的方法来获取 Activity 中的元素。所有 Element 后带 s 的函数,均获得所有匹配的元素,不带 s 的函数获得第一个匹配的元素。

查询函数

1. findElement(s)ByName

在 Android 中基本没用。Android UI 没有 Name 这个属性。有说可以使用 text 值获取。但我并没有成功

2. findElement(s)ByClassName

通过类名来获取元素,用法如下:


  
  
  1. item_list = dr.find_elements_by_class_name("android.widget.LinearLayout"
  2. item_list[2].click() 

3. findElementById

通过 resource_id 来获取元素,每个 Activity 中都是唯一的,用法如下


  
  
  1. t = dr.find_element_by_id("com.tencent.mm:id/f7"
  2. t.send_keys(wechatId) 

4. findElement(s)ByAccessbiltiyId

在 Android 上 AccessbilityID 实际就是 contentDescription 。这个属性是为了方便视力受损人士使用手机所设置。开启 TTS 后系统会朗读相关控件的 contentDescription。

5. findElement(s)ByXPath

通过 XML Path 描述来寻找元素。我没有成功的获取到,可能是 XPath 写的有问题。


  
  
  1. s = dr.find_element_by_xpath("//android.widget.TextView[contains(@text,'搜索')]"
  2. s.click() 

6. findElementByAndroidUIAutomator

通过 UIAutomator 的选择器来获取元素。因为 Appium 在 Android 上实际是调用的 UIAutomator,所以可以通过 UIAutomator 的选择器来选择元素。


  
  
  1. el = dr.find_element_by_android_ui_automator("new UiSelector().text(\"搜索\")"
  2. el.click() 

操作函数

操作函数用于操作选定的元素,有很多,以下仅列举几个,更多的请查阅手册。

  • click
  • send_keys
  • clear

查询函数返回的元素对象可以像 JS 中的 dom 元素一样,继续使用查询函数来选定其子元素。用例如下。


  
  
  1. search = dr.find_element_by_id("com.tencent.mm:id/aqw").find_element_by_class_name("android.widget.RelativeLayout"
  2.  
  3. search.click() 

如何确定查询规则

了解了相关的函数后,下面就应对 UI 进行定位了。如果是自己团队开发的程序,推荐让开发同学在所有的空间上都添加 resource_id 进行绝对定位。如果碰到没有谈价 resource_id 的元素,那就要使用别的办法进行定位了。

1. UI Automator Viewer

UI Automator Viewer 是 Android 官方的 UI 定位工具,位于 sdk/tools 下。运行后会打开 viewer 界面。点击获取按钮即可获取当前正在运行的 Activity 的 UI 结构。

2. AppiumDriver getPageSource

AppiumDriver(Client) 可以很方便的获得当前正在运行的 Activity 的 UI 描述,随后可根据返回的 XML 文档来寻找元素。


  
  
  1. print dr.page_source 

确定元素位置后,即可根据前述的 Find 方法来查找/选择元素

编写完整的测试代码

正确的获取元素之后便可以获取元素相关的信息,随后使用各语言常用的测试框架编写测试即可,如 Java 的 JUnit,Nodejs 的 Mocha 等。

这里我使用 Appium 主要是为了模拟用户点击添加微信好友,所以完整的程序并没有使用到测试框架。相关的 UI 元素获取/操作方法供大家参考。


  
  
  1. # coding:utf-8 
  2. from appium import webdriver 
  3. from time import sleep 
  4.  
  5.  
  6. def addFriend(dr, id, dryRun=False): 
  7.     succ = False 
  8.     wechatId = str(id) 
  9.     dr.find_element_by_accessibility_id(r"更多功能按钮").click() 
  10.     item_list = dr.find_elements_by_class_name("android.widget.LinearLayout"
  11.     try: 
  12.         item_list[2].click() 
  13.     except
  14.         print "Error! in item list len" 
  15.         return succ 
  16.     el = dr.find_element_by_class_name("android.widget.ListView"
  17.     item_list = el.find_elements_by_class_name("android.widget.LinearLayout"
  18.     try: 
  19.         item_list[1].click() 
  20.     except
  21.         print "Error! in item list len" 
  22.         return succ 
  23.     t = dr.find_element_by_id("com.tencent.mm:id/f7"
  24.     t.send_keys(wechatId) 
  25.     search = dr.find_element_by_id("com.tencent.mm:id/aqw").find_element_by_class_name("android.widget.RelativeLayout"
  26.     search.click() 
  27.     try: 
  28.         freq = dr.find_element_by_id('com.tencent.mm:id/aqq'
  29.         assert freq.text == u"操作过于频繁,请稍后再试。" 
  30.         print "Frequency too high! Sleep 300s" 
  31.         sleep(60) 
  32.         return succ 
  33.     except
  34.         pass 
  35.  
  36.     try: 
  37.         dr.find_element_by_id('com.tencent.mm:id/a8x').click() 
  38.         addBtn = dr.find_element_by_id('com.tencent.mm:id/eu'
  39.         if not dryRun: 
  40.             addBtn.click() 
  41.             succ = True 
  42.         print "Success Send Requests:" + wechatId 
  43.     except
  44.         print "No Such User Or Already a Friend:" + wechatId 
  45.  
  46.     while True
  47.         try: 
  48.             dr.find_element_by_id('com.tencent.mm:id/fb').click() 
  49.         except
  50.             try: 
  51.                 dr.find_element_by_id('com.tencent.mm:id/f4').click() 
  52.             except
  53.                 break 
  54.     return True 
  55.  
  56. def resetActivity(dr, desired_caps): 
  57.     dr.start_activity(desired_caps['appPackage'], desired_caps['appActivity']) 
  58.  
  59. desired_caps = {} 
  60. desired_caps['platformName'] = 'Android' 
  61. desired_caps['platformVersion'] = '5.1' 
  62. desired_caps['deviceName'] = 'm3_note' 
  63. desired_caps['appPackage'] = 'com.tencent.mm' 
  64. desired_caps['appActivity'] = '.ui.LauncherUI' 
  65. print "Trying connect to phone..." 
  66. dr = {} 
  67. try: 
  68.     dr = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) 
  69. except Exception, e: 
  70.     print "Cannot Connect to phone :", e 
  71.     exit() 
  72. print "Successfully connect to phone." 
  73. print "Reading friend list..." 
  74. friendList = [] 
  75. fp = open("friends.txt"
  76. line = fp.readline().strip() 
  77. while line: 
  78.     friendList.append(line) 
  79.     line = fp.readline().strip() 
  80. print "Finish reading friends. Total: " + str(len(friendList)) 
  81. print "Wait for Wechat's splash screen...." 
  82. for i in range(0, 10): 
  83.     print 10 - i 
  84.     sleep(1) 
  85. succ_list = [] 
  86. fail_list = [] 
  87. for i in friendList: 
  88.     try: 
  89.         succ = addFriend(dr, i, dryRun=False
  90.         if succ: 
  91.             succ_list.append(i) 
  92.         else
  93.             fail_list.append(i) 
  94.     except
  95.         fail_list.append(i) 
  96.         resetActivity(dr, desired_caps) 
  97.  
  98. print "Succeed List:" 
  99. print "\n".join(succ_list) 
  100. print "Failed List:" 
  101. print "\n".join(fail_list) 
  102.  
  103. dr.close() 





本文作者:佚名
来源:51CTO
目录
相关文章
|
3月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
353 4
|
1天前
|
缓存 Java 测试技术
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
14 3
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
|
16天前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
121 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
14天前
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
37 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
1月前
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
36 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
2月前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
92 14
|
2月前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。
|
2月前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
2月前
|
搜索推荐 Android开发 开发者
安卓应用开发中的自定义控件实践
在安卓应用开发的广阔天地中,自定义控件如同璀璨的星辰,点亮了用户界面设计的夜空。它们不仅丰富了交互体验,更赋予了应用独特的个性。本文将带你领略自定义控件的魅力,从基础概念到实际应用,一步步揭示其背后的原理与技术细节。我们将通过一个简单的例子——打造一个具有独特动画效果的按钮,来展现自定义控件的强大功能和灵活性。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往更高阶UI设计的大门。
|
2月前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
88 0

热门文章

最新文章

  • 1
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    14
  • 2
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    28
  • 3
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    34
  • 4
    Android历史版本与APK文件结构
    121
  • 5
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    29
  • 6
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    23
  • 7
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
    60
  • 8
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    37
  • 9
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
    73
  • 10
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    121