博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【备档】客户端自动化(主Android Appium + python
阅读量:5242 次
发布时间:2019-06-14

本文共 6720 字,大约阅读时间需要 22 分钟。

之前做分享写的文档,备档~

0.移动客户端自动化简介

客户端自动化测试的本质

定位对象 · 操作对象 · 校验对象

对象的定位应该是自动化测试的核心,要想操作、校验一个对象,首先应该识别这个对象。

一个对象具有特定的属性,譬如:文字、类型、位置等等。我们可以通过这些属性找到这对象。

移动客户端自动化测试常见框架

Android

  1. Monkey
  2. Monkeyrunner
  3. UIautomator
  4. Robotium

iOS

  1. UIAutomation

通用

  1. Appium
  2. Calabash
    ...

框架选择

  1. 支持平台,系统版本
  2. 是否需要源码
  3. 脚本语言
  4. 是否支持webview
    ...

浅谈移动端自动化测试框架和工具

iOS自动化测试框架对比

1.Appium 思想·原理·环境搭建

Appium 思想

你无需为了自动化,而重新编译或者修改你的应用。
你不必局限于某种语言或者框架来写和运行测试脚本。
  →Appium 真正的工作引擎其实是第三方自动化框架
  →把这些第三方框架封装成一套 API,WebDriver API.WebDriver(也就是 “Selenium WebDriver") 指定了客户端到服务端的协议。
  →Selenium 是web自动化测试工具集,核心是RC(selenium 1.0)和WebDriver(selenium 2.0)
  →RC和WebDriver 定义客户端脚本与浏览器交互的协议。以及元素定位与操作的接口。
   
一个移动自动化的框架不应该在接口上重复造轮子。
   →WebDriver 已经成为 web 浏览器自动化的标准,也成了 W3C 的标准 —— W3C Working Draft,并扩充了 ,在原有的基础上添加移动自动化相关的 API 方法
无论是精神上,还是名义上,都必须开源。 

架构原理

  • 左边的WebDriver script是我们的selenium测试脚本
  • 中间是起的Appium的服务,Appium在这边起了一个Server,Appium Server接收webdriver 标准请求,解析请求内容,调⽤用对应的框架响应操作。如:脚本发送一个点击按钮的请求给appium server
  • Appium server会把请求转发给中间件Bootstrap.jar ,它是用java写的,安装在手机上.Bootstrap 接收appium 的命令,最终通过调⽤用UiAutomator的命令来实现
  • 最后执⾏行的结果由Bootstrap返回给Appium server

 

Appium环境搭建python篇(mac系统)

安装时使用VPN可能比淘宝源成功率更高~

 

2.定位对象 · 操作对象 · 校验对象

定位对象-Android

工具

UiAutomatorview (4.1下版本不支持)

启动方法 

  ~ uiautomatorviewer

定位方法

查找客户端页面元素方法

以下是Appium给出的所有方法(但不一定支持!)

查找页面中存在的单个元素
查找页面中存在多个元素(返回数组)
查找方法

find_element

find_elements
def find_element(self, by=By.ID, value=None)

被其他find_element方法调用

find_element_by_accessibility_id find_elements_by_accessibility_id

Accessibility ID在Android上面就等同于contentDescription,这个属性是方便一些生理功能有缺陷的人使用应用程序的。

UiAutomatorview中content-desc

find_element_by_android_uiautomator find_elements_by_android_uiautomator 使用android_uiautomator表达
find_element_by_class_name find_elements_by_class_name UiAutomatorview中class
find_element_by_id find_elements_by_id UiAutomatorview中resource-id
find_element_by_ios_uiautomation find_elements_by_ios_uiautomation -
find_element_by_link_text find_elements_by_link_text UiAutomatorview中text
find_element_by_name find_elements_by_name Appium 1.5 版本已经被废除
find_element_by_partial_link_text find_elements_by_partial_link_text

UiAutomatorview中text,可以匹配部分文字

譬如:美食(XX家)

find_element_by_tag_name find_elements_by_tag_name Appium 1.0 版本已经被废除
find_element_by_xpath find_elements_by_xpath xpath,强烈不推荐

 

find_element_by_android_uiautomator() 举栗子

 

def autotest_find_name_by_uiautomator(self, name):    return self.driver.find_element_by_android_uiautomator('new UiSelector().text("%s")' % name)

  

find_element_by_android_uiautomator()中的字符串为Uiautomator的写法,主要有以下几种方法:

 

new UiSelector().text("%s")new UiSelector().textContains("%s")new UiSelector().className("%s")new UiSelector().resourceId("%s")

 

textContains类似于find_element_by_partial_link_text,可以做部分文字匹配

操作对象

以下是常用的方法,更多的方法可以通过源码或提示获得

tips:某些方法可能在特定系统不支持

# 点击对象.click() # 文本框输入文字.send_keys("%s")#获取控件文字.text  # 从(startx,starty)滑到(endx,endy),分duration步滑,每一步用时是5毫秒。driver.swipe(int startx, int starty, int endx, int endy, int duration)  # 按手机固定键,key值定义在AndroidKeyCode类中# keycode http://blog.csdn.net/crisschan/article/details/50419963driver.send_key_event(int key)  # 获取当前的activitydriver.current_activity() # 等待指定的activity出现,interval为扫描间隔1秒driver.wait_activity(activity, timeout, interval=1)  ...

  

校验对象

在Python环境下,Appium 官方推荐使用unittest来维护测试用例,unittest提供了多种assert方法,我们可以通过这些方法来做校验。

unittest中常用的assert语句

校验方式

  • 校验控件是否展示
  • 校验控件中的数据(文本)是否正确
  • 图片对比
  • ...

代码实现

校验元素非空

def assert_element_exist_by_x(self, how, what, msg=None):    """    通过*方法验证元素非空    :param how:find_element_by_* methods    (By.CLASS_NAME/By.TAG_NAME/By.NAME/By.PARTIAL_LINK_TEXT/By.NAME/By.XPATH/By.ID)    :param what:    :param msg:    """    try:        if how ==By.NAME:            self.assertIsNotNone(self.autotest_find_name_by_uiautomator(what), msg)        else:            self.assertIsNotNone(self.driver.find_element(by=how, value=what), msg)        return True    except Exception:        print "xxxxx"

   

3.用例编写

官方栗子

import osimport unittestfrom appium import webdriverfrom time import sleep# Returns abs path relative to this file and not cwdPATH = lambda p: os.path.abspath(    os.path.join(os.path.dirname(__file__), p))class ContactsAndroidTests(unittest.TestCase):    def setUp(self):        desired_caps = {}        desired_caps['platformName'] = 'Android'        desired_caps['platformVersion'] = '4.2'        desired_caps['deviceName'] = 'Android Emulator'        desired_caps['app'] = PATH(            '../../../sample-code/apps/ContactManager/ContactManager.apk'        )        desired_caps['appPackage'] = 'com.example.android.contactmanager'        desired_caps['appActivity'] = '.ContactManager'        self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)    def tearDown(self):        self.driver.quit()    def test_add_contacts(self):        el = self.driver.find_element_by_accessibility_id("Add Contact")        el.click()        textfields = self.driver.find_elements_by_class_name("android.widget.EditText")        textfields[0].send_keys("Appium User")        textfields[2].send_keys("someone@appium.io")        self.assertEqual('Appium User', textfields[0].text)        self.assertEqual('someone@appium.io', textfields[2].text)        self.driver.find_element_by_accessibility_id("Save").click()        # for some reason "save" breaks things        alert = self.driver.switch_to_alert()        # no way to handle alerts in Android        self.driver.find_element_by_android_uiautomator('new UiSelector().clickable(true)').click()        self.driver.press_keycode(3)if __name__ == '__main__':    suite = unittest.TestLoader().loadTestsFromTestCase(ContactsAndroidTests)    unittest.TextTestRunner(verbosity=2).run(suite)

   

setup

在Appium中所有动作的前提是要启动一个session,启动方法就是

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

其中desired_caps是配置信息,它告诉server 本次测试的具体内容,譬如:

  • 本次测试是启动浏览器还是启动移动设备?
  • 是启动andorid还是启动ios?
  • 启动android时,app的package是什么?
  • 启动android时,app的activity是什么?

必要的desired_caps参数

desired_caps['platformName'] = 'Android'desired_caps['platformVersion'] = '4.2'desired_caps['deviceName'] = '022MWW146T007732'desired_caps['app'] = 'XXX.apk'
  • platformName:使用哪种移动平台。iOS, Android, orFirefoxOS?
  • deviceName:启动哪种设备,是真机还是模拟器?iPhone Simulator, iPad Simulator, iPhone Retina 4-inch, Android Emulator, Galaxy S4, etc...
  • app:应用的绝对路径,注意一定是绝对路径。如果指定了appPackage和appActivity的话,这个属性是可以不设置的。另外这个属性和browserName属性是冲突的。
  • automationName:使用哪种自动化引擎。appium(默认)还是Selendroid?
  • appActivity:待测试的app的Activity名字。比如MainActivity, .Settings。注意,原生app的话要在activity前加个"."。
  • appPackage:待测试的app的java package。比如com.example.android.myApp, com.android.settings。

teardown

self.driver.quit()

 

4.其他

  • Android 获取当前Activity、包名方法
    adb shell dumpsys activity | grep "mFocusedActivity"
    adb shell pm list package
  • 元素定位不到/没有id的方法
    麻烦开发增加特有、不重复的id

 

转载于:https://www.cnblogs.com/silvi/p/7156762.html

你可能感兴趣的文章
jquery的$(document).ready()和onload的加载顺序
查看>>
Python Web框架Django (五)
查看>>
.net学习之继承、里氏替换原则LSP、虚方法、多态、抽象类、Equals方法、接口、装箱拆箱、字符串------(转)...
查看>>
【codevs1033】 蚯蚓的游戏问题
查看>>
【程序执行原理】
查看>>
python的多行注释
查看>>
连接Oracle需要jar包和javadoc文档的下载
查看>>
UVA 10976 - Fractions Again?!
查看>>
Dreamweaver cc新版本css单行显示
查看>>
【android】安卓的权限提示及版本相关
查看>>
JavaScript可否多线程? 深入理解JavaScript定时机制
查看>>
IOS基础学习
查看>>
PHP 导出 Excell
查看>>
Java基础教程——网络基础知识
查看>>
Kruskal基础最小生成树
查看>>
ubuntu 14.04 安装搜狗拼音输入法
查看>>
浅谈算法和数据结构: 一 栈和队列
查看>>
Java内部类详解
查看>>
【hdu 1429】胜利大逃亡(续)
查看>>
图论-次短路求法
查看>>