Android自动化(一)

自动化工具选择

工具名称 被测系统 测试 脚本语言 支持H5 跨应用 稳定性 SDK自带
MonKeyRunner Android 功能 Python 支持 稳定
Instrumentation Android(<4.1) 功能 Java 支持 可以 稳定
Uiautomator2 Android(>=4.1) 功能 Java 支持 可以 稳定
Adb-For-Test Android(>=4.1) 功能 Java/Python 支持 可以 稳定
Monkey Android 稳定 Java 稳定
CTS Android 兼容 Java 支持 可以 稳定
Uiautomation iOS 功能 JS 支持 可以 稳定 Xcode自带
Calabash Android,iOS 功能 Ruby 支持 可以 一般
Appium Android,iOS 功能 Java/Python/jS/C/c#/Perl 支持 可以 一般

Appium生态工具

  • adb:Android的控制工具,用于获取Android的各种数据和控制
  • Appium Desktop:内嵌了appium server和inspector的综合工具
  • Appium Server:appium的核心工具、命令行工具
  • Appium client:各种语言的客户端封装库,用于连接appium server
    • python、java、ruby、robotframework-appium
  • AppCrawlar自动遍历工具

环境安装

  • Java 1.8版本(配置环境变量)
  • Android SDK(配置环境变量)
  • Appium Desktop
  • Python3
  • Appium python client

Android自动化前提依赖

  • android sdk:Android Studio可辅助安装
  • 模拟器
    • Android Studio⾃带emulator [推荐]
    • Genymotion
    • BlueStacks
  • 真机
  • Appium Desktop:⼊门学习⼯具

获取app的信息

  • app信息
    • 获取当前界⾯元素:adb shell dumpsys activity top
    • 获取任务列表:adb shell dumpsys activity activities
  • app⼊口
    • adb logcat |grep -i displayed
    • aapt dump badging mobike.apk | grep launchable-activity
    • apkanalyzer 最新版本的sdk中才有
  • 启动应⽤
    • adb shell am start -W -n com.xueqiu.android/.view.WelcomeActivityAlias -S

Android的capability

启动app后执行命令adb logcat | grep Displayed,获取到app的包名和activityid:包名/activityid
Appium需要设置好设备信息:Automatic Server->Desired Capabilities

信息填写

from appium import webdriver
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "test"
caps["appPackage"] = "com.xueqiu.android"
caps["appActivity"] = ".view.WelcomeActivityAlias"
caps['autoGrantPermissions'] = True
caps['noreset']=True
caps['automationName']='uiautomator2'

driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
self.driver.implicitly_wait(5)

Capability 简介

  • 功能:配置 Appium 会话,告诉 Appium 服务器需要自动化的平台的应用程序
  • 形式:键值对的集合,键对应设置的名称,值对应设置的值

platformName:平台,Android/iOS
deviceName:设备名
appPackage:应用的包名
appActivity:应用的页面名 Activity
noReset: 防止清空缓存信息

主要分为三部分

  • 公共部分
  • ios 部分
  • android 部分

Session

  • Appium 的客户端和服务端之间进行通信的前提
  • 通过 Desired Capabilities 建立会话

公共部分参数配置

描述
platformName 使用的手机操作系统 iOS,Android,或者 Firefox0S
platformVersion 手机操作系统的版本 例如 7.1, 4.4
deviceName 使用的手机或模拟器类型 iPhone Simulator, iPad Simulator, iPhone Retina 4-inch, Android Emulator, Galaxy S4, 等等…. 在 iOS 上,使用 Instruments的 instruments -s devices 命令可返回一个有效的设备的列表。在 Andorid 上虽然这个参数目前已被忽略,但仍然需要添加上该参数
automationName 使用哪个自动化引擎 android默认使用uiautomator2,ios默认使用XCUTest
noReset 在当前 session 下不会重置应用的状态。默认值为 false true, false
udid 连接的真实设备的唯一设备编号 (Unique device identifier) 例如 1ae203187fc012g

Android 部分特有参数配置

描述
appActivity Activity 的名字是指从你的包中所要启动的 Android acticity。他通常需要再前面添加. (例如 使用 .MainActivity 代替 MainActivity) MainActivity, .Settings
appPackage 运行的 Android 应用的包名 com.example.android.myApp, com.android.settings
appWaitActivity 用于等待启动的 Android Activity 名称 SplashActivity
unicodeKeyboard 启用 Unicode 输入,默认为 false true or false
resetKeyboard true or false
dontStopAppOnReset 首次启动的时候,不停止 app true or false
skipDeviceInitialization 跳过安装,权限设置等操作 true or false

iOS 独有

描述
bundleId 被测应用的 bundle ID 。用于在真实设备中启动测试,也用于使用其他需要 bundle ID 的关键字启动测试。在使用 bundle ID 在真实设备上执行测试时,你可以不提供 app 关键字,但你必须提供 udid 。 例如 io.appium.TestApp
autoAcceptAlerts 当 iOS 的个人信息访问警告 (如 位置、联系人、图片) 出现时,自动选择接受( Accept )。默认值 false true 或者 false
showIOSLog 是否在 appium 日志中显示从设备捕获的任何日志。 默认 false

配置优化

  • 添加参数,提高用例的稳定性
{
  "noReset": "true", // 不清空缓存信息
  "dontStopAppOnReset": "true", // 首次启动的时候,不停止app
  "skipDeviceInitialization": "true", // 跳过安装,权限设置等操作
  "unicodeKeyBoard": "true" // 输入中文
}

appium功能键

  • SelectElements:选中元素,查看层级和属性
  • Swipe By Coordinates:通过坐标点滑动
  • Tap By Coordinates:通过坐标点点击
  • Back:返回
  • Refresh Source & Screenshot:刷新页面
  • StartRecording:开始录制脚本
  • Search for element:搜索元素
  • Copy XML Source to Clipboard:复制 xml 结构
  • Quit Session & Close Inspector:退出当前 Session

元素定位方式

1、ID定位,两种方法

find_element_by_id('user_login')
find_element(By.ID, 'user_login')

2、name定位

find_element_by_name('commit')
find_element(By.NAME, 'commit')

3、class定位

find_element_by_class_name('filter')
find_element(By.CLASS_NAME, 'user_login')

4、tag定位

find_element_by_tag_name()
find_element(By.TAG_NAME, 'user_login')

5、link定位

find_element_by_link_text()
find_element(By.LINK_TEXT, '社区')

6、partial link定位

find_element_by_partial_link_text()
find_element(By.PARTIAL_LINK_TEXT, 'user_login')

7、XPath定位

find_element(By.XPATH, "//a[contains(@title,'20190728')]")
find_element_by_xpath("//a[@id='user_login']")
find_element_by_xpath("//a[@name='user_login']")
find_element_by_xpath("//a[@class='user_login']")
find_element_by_xpath("//*[@id='user_login']")
find_element_by_xpath("//a[@type='submit']")
find_element_by_xpath('//a[contains(text(), "问卷")]/a')

//表示当前页面某个目录下, a表示定位元素的标签名,[@id="user_login"]表示这个元素的id属性值,(@title,'20190728')表示这个元素的title属性值,如果不想指定标签名,则可以用星号(*)代替,元素的任意属性值都可以使用,只要它能唯一的标识一个元素。

  • 层级与属性结合
    如果一个元素本身没有可以唯一标识这个元素的属性值,那么我们可以找其上一级元素,或上上级元素。
    find_element_by_xpath("//span[@class='class名称']/span/input")
  • 使用逻辑运算符
    如果一个属性不能唯一区分一个元素,我们还可以使用逻辑运算符连接多个属性来查找元素
    find_element_by_xpath("//input[@id='值' and @class='值']/span/input")
    8、CSS选择器定位
find_element(By.CSS_SELECTOR, '.filter.nav.nav-pills .active')
find_element(By.CSS_SELECTOR, '.title [title*="先到先得')
find_element(By.CSS_SELECTOR, '.media-heading>span')
find_element(By.CSS_SELECTOR, 'a[href$="82"]')
find_element(By.CSS_SELECTOR, 'a:nth-child(2)') # a标签的第二个子元素
CSS XPATH
.title a //div/a
[attribute*="subString"] //*[contains(@attribute,"sub")]

9、定位一组元素

获取标签名为a的所有元素,获取链接中包含12345的元素
hrefs = self.driver.find_elements(By.TAG_NAME, 'a')
for href in hrefs:
    if href.get_attribute('title') == '先到先得':
            input.click()

10、MobileBy

from selenium.webdriver.common.by import By


class MobileBy(By):
    IOS_PREDICATE = '-ios predicate string'
    IOS_UIAUTOMATION = '-ios uiautomation'
    IOS_CLASS_CHAIN = '-ios class chain'
    ANDROID_UIAUTOMATOR = '-android uiautomator'
    ANDROID_VIEWTAG = '-android viewtag'
    ACCESSIBILITY_ID = 'accessibility id'
    IMAGE = '-image'
    CUSTOM = '-custom'

继承的是By,所以用法和By是一样的,示例:

self.driver.find_element(MobileBy.XPATH, "//*[@text='交易']")

测试用例重要组成部分

  • 导入依赖:
    • python:from import
    • java:import
  • capabilities设置
    • python:dict
    • java:class
  • 初始化driver
  • python:webdriver.remote
    • java:new AppiumDriver
  • 元素定位与操作:find+action
  • 断言:assert

capabilities设置

  • app apk地址
  • appPackage 包名
  • appActivity Activity名字
  • automationName 默认使⽤uiautomator
  • noReset fullReset 是否在测试前后重置相关环境
  • unicodeKeyBoard resetKeyBoard 是否需要输⼊⾮英⽂
    之外的语⾔并在测试完成后重置输⼊法

控件基础知识

  • dom:Document Object Model ⽂档对象模型
  • dom应⽤:最早应⽤于html和js的交互。界⾯的结构化描述,常见的格式为html、xml。核⼼元素为节点和属性
  • xpath:xml路径语⾔,⽤于xml中的节点定位
    app dom为例:
  • node
  • attribute
    • clickable
    • content-desc
    • resource-id
    • text
    • bounds
  • iOS与Android的区别
    • dom属性和节点结构类似
    • 名字和属性的命名不同

常用api

  • click:点击
  • send_keys:输入
  • get_attribute:获取元素属性
  • page source:
    def test_profile(self):

        self.driver.find_element_by_id("user_profile_icon").click()

    def test_click(self):
        self.driver.tap() # 根据位置进行点击,参数是坐标位置

    def test_sendkeys(self):
        self.driver.keyevent() # 键盘控件,输入内容
    def test_get_attribute(self):
        print(self.driver.find_element_by_id("user_profile_icon").get_attribute("class"))

    def test_source(self):
        print(self.driver.find_element_by_id("user_profile_icon").get_attribute("class"))
        print(self.driver.page_source)

    def test_selected_delete(self):
        pass
        #self.driver.find_element_by_xpath("//*[@text='行情']").click()
        #self.driver.find_element_by_xpath("//*[contains(@text, '新增手势')]").click()
    def test_swipe(self):

        for i in range(5):
            self.driver.swipe(500, 900, 100, 200, 1000)

TouchAction

  • 长按
  • 滑动

定位

  • 测试步骤三要素:

    • 定位、交互、断⾔
  • id

  • aid

  • xpath

  • uiautomator

  • accessibityId: content-desc


    uiautomator2的定位操作.png
  • 不推荐:class -ios -android

toast识别

  • toast原理
  • toast识别方法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容