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识别方法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容