ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

APP自动化你需要知道的一

2021-05-16 16:59:35  阅读:263  来源: 互联网

标签:appium 需要 text self driver element 自动化 android APP


appium环境安装与架构

目前mobile自动化的方案

IOSAndroid
calabash-ios/Frank/UIAutomation/ios-driver/KeepItFunctional…calabash-android/MonkeyTalk/Robotium/UIAutomator/selendroid…

Appium是一个移动端的自动化测试框架,可用于测试原生应用,移动网页应用和混合应用,且是跨平台的,可适用于Android操作系统和IOS操作系统。原生应用是指用android或者IOS编写的应用,移动网页指的是网页应用,类似于IOS中safari应用或者Chrome应用或者类似浏览器的这种应用;混合应用是指一种包裹webview的应用,原生应用网页内容交互性的应用;Appium底层多引擎可切换,并且生态丰富,社区强大
Appium的设计理念

  1. webdriver是基于http协议的,第一次连接会建立一个session会话,并通过post发送一个json告知服务端相关测试信息
  2. Client/Server设计模式(客户端通过WebDriver json wire协议与服务端通信,多语言支持)
  3. Server可以放在任何地方,只要能连接手机即可
  4. 服务端NODEJS开发的HTTP服务
  5. appium使用appium-xcuitest-driver来测试iPhone设备,其中需要安装facebook出的WDA(webdriveragent)来驱动IOS测试
    Appium环境生态工具以安卓手机为例
    adb:android的控制工具,用于获取android的各种数据和控制
    Appium Desktop:内嵌了appium server和inspector的综合工具
    Appium Server:appium的核心工具,命令行工具
    Appium client:各种语言的客户端封装库,用于连接appium-server
    安装Java环境,建议java1.8,下载完成后需要配置环境变量下载地址
    安装Android sdk下载地址
    安装Node js(>=10版本),npm(>=6版本)
    安装python3
    appium-desktop
    Appium python client
    总之
    要想支持手机端,我们需要安装JDK和SDK
    要想完成客户端的安装需要安装appium python client
    要想完成appium server的安装需要安装Node js,appium server,appium-desktop
    通过输入appium -version进行检查是否环境安装成功
    在这里插入图片描述
    将appium所有的所有相关的环境变量配置好之后,我们开始使用appium进行测试,我们打开appium,我们使用桌面版,打开之后,都使用默认信息即可,appium会自动帮我们起端口4723的服务,我们点击start inspect session,我们会进入到我们一个用来元素定位的页面
    在这里插入图片描述
    在这里插入图片描述
    B区域应该是当前dom的层级,这里面包含它的元素、布局以及一些标签
    C区域显示的是选中元素的属性信息
    A区域:
    第一个按钮Select Elements表示的是选中一个元素
    第二个按钮swipe By Coordinates表示的是通过坐标点进行滑动
    第三个按钮Tap By Coordinates表示的是通过坐标点进行点击
    第四个按钮Back表示的是返回上级页面
    第五个按钮Refresh Source & Screenshot表示的是对当前页面进行刷新
    第六个按钮Start Recording表示的是开始录制脚本
    第七个按钮Search for element表示的是搜素元素
    第八个按钮Copy XML Source to Clipboard表示的是复制层级结构
    第九个按钮Quit Session & Close Inspector表示的是关闭会话
    在此过程中,我们需要获取app的信息
    app信息:
    获取当前页面元素:adb shell dumpsys activity top
    获取任务列表adb shell dumpsys activity activities
    adb shell dumpsys window|grep mCurrent #获取当前页面的包名和activity name
    app入口:
    adb logcat | grep -i displayed #获取 app入口packagename 和activityname
    adb logcat |grep -i ‘activitymanager’ # 也可以获取 app入口的包名和页面名,有的时候使用上面的命令拿不到启动页面的名称,可以使用这个命令
    aapt dump badging mobike.apk | grep launchable-activity #分析 apk包 获取包名和启动页名
    启动应用
    adb shell am start -W -n com.xiaomi.shop/com.xiaomi.shop.activity.MainTabActivity -S

appium元素定位和隐式等待

desirecapability介绍
官方文档:https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md
desirecapability是客户端与server端建立连接的json串,由它告诉服务器我们测试设备的信息,
app apk地址
appPackage包名
appActivity Activity 名字
noReset fullRest是否在测试前后重置相关环境(例如首次打开弹窗或者是登陆信息)
unicodeKeyBoard resetKeyBoard是否需要输入非英文之外的语言并在测试完成后重置输入法
dontStopAppOnReset首次启动的时候,不停止app
skipDeviceInitialization跳过安装,权限设置等操作
我们运行一个试下
代码如下

from appium import webdriver

class TestWeChat():

  def setup(self):
    desire_caps = {
      "platformName": "android",
      "deviceName": "127.0.0.1:7555",
      "appPackage": "com.xueqiu.android",
      "appActivity": ".view.WelcomeActivityAlias",
        "noReset": "true",  #首页弹窗取消
      "unicodeKeyBoard" : "true",
      "resetKeyBoard" : "true"
    }
    self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_capabilities=desire_caps)
    #隐式等待
    self.driver.implicitly_wait(10)

  def teardown(self):
    #强制等待
    time.sleep(2)
    self.driver.quit()

  def test_demo(self):
    self.driver.find_element_by_id("com.xueqiu.android:id/home_search").click()
    self.driver.find_element_by_id("com.xueqiu.android:id/search_input_text").send_keys("小米")
    print("测试很好")

我们运行test_demo这个测试用例
结果能够正常运行
在这里插入图片描述

appium元素定位
我们先了解下Android的一些基础知识:
Android是通过容器的布局属性来管理子控件的位置关系,布局过程就是把界面上的所有控件根据他们的间距的大小,摆放在正确的位置
Android七大布局:
LInearLayout——线性布局,可以理解为横线或者纵向的布局
RelativeLayout——相对布局,比如说我们的通讯录,头像和名称应该就是一个相对布局
FrameLayout——帧布局
TableLayout——表格布局,与网格布局类似,就是把我们的图片等信息以表格的形式进行布局
absoluteLayout——绝对布局,可以理解为根据绝对坐标进行布局
GridLayout——网格布局
ConstraintLayout——约束布局
Android四大组件

  1. activity——与用户交互的可视化界面
  2. service——实现程序后台运行的解决方案
  3. content provider——内容提供者、提供程序所需要的数据
  4. broadcast receiver——广播接收器监听外部事件的到来,比如说来电、短信等
    Android常用控件
    TextView(文本控件), EditText(可编辑文本控件)
    Button(按钮), ImageButton(图片按钮) ToggleButton(开关按钮)
    ImageView(图片控件), CheckBox(复选框控件)RadioButton(单选框控件)
    **那什么是布局呢?**布局是一种可用于放置很多控件的容器,它可以按照一定的规律调整内部控件的位置,从而编写出精美的界面。当然,布局的内部除了放置控件外,也可以放置布局,通过多层布局的嵌套,我们就能够完成一些比较复杂的界面;对于IOS来说,是直接用变量之间的相对关系完成位置的计算
    元素的定位实际上就是定位控件,当然我们也可以通过布局进行定位
    dom:Document Object Model文档对象模型
    dom应用:最早应用于html和js的交互,用于表示界面的控件层级,界面的结构化描述,常见的格式为html\xml,核心元素为节点和属性
    xpath:xml路径语言,用于xml中的节点定位
    Android应用的层级结构与html不一样,是一个定制的xml
    app source类似于dom,表示app的层级,代表了界面里面所有的控件树的结构
    每个控件都有它的属性(包括resourceid,xpath,id属性),没有CSS属性
    如果只是测试安卓设备,我们也可以通过uiautomatorviewer工具进行元素定位,uiautomatorviewer是安卓SDK自带的定位工具,我们直接运行uiautomatorviewer.bat文件,即可将我们的APP映射到该工具上,相比于appium inspector,它更加直接;不过个人更喜欢appium inspector,因为appium inspector在我们定位的时候,可以进行检查我们的定位是否是准确的
    目前我的手机安卓版本是10,使用uiautomatorviewer直接报错了,晚上说了很多方法,表示看不是很懂,这里我介绍一个我的操作的方法
    首先将这个地方的代码下载下来,可以下载该源码的zip包https://github.com/yaming116/uiautomatorview
    解压这个zip包,然后找到这两个文件
    在这里插入图片描述
    然后我们将uiautomatorviewer.jar包复制到我们D:\android\sdk\tools\lib这个目录下,替换到原来的jar包
    之后我们需要将LvmamaXmlKit.jar包push到手机,使用命令adb push D:\LvmamaXmlKit.jar /data/local/tmp/
    在这里插入图片描述
    之后我们重新打开uiautomatorviewer即可
    在这里插入图片描述
    在这里插入图片描述
    左侧是我们手机APP的映射
    左上方第一个按钮打开文件,第二个按钮含义是映射手机APP页面;第三个按钮含义同第二个按钮,但是对整个页面的dom层级进行压缩了
    右侧上方可以理解为页面布局;右侧下方可以理解为元素的属性
    等待
    分为强制等待、隐式等待和显示等待,具体会在之后的代码中体现

APP控件交互

元素的常用方法
点击方法 element.click()
输入操作element.send_keys(“appium”)
设置元素的值element.set_value(“appium”)
清除操作element.clear()
是否可见element.is_displayed()返回True/false
是否可用element.is_enabled()返回True/False
是否被选中element.is_selected()返回True/False
获取属性值get_attribute(name)
源码位置:https://github.com/appium/appium-uiautomator2-server/blob/master/app/src/main/java/io/appium/uiautomator2/handler/GetElementAttribute.java
元素的常用属性
1、获取元素文本
格式:element.text
2、获取元素坐标
格式:element.location
结果:{‘y’:‘19’, ‘x’:‘39’},一般是左上角的坐标
3、获取元素尺寸
格式:element.size
结果:{‘width’:500,‘height’:22}
使用uiautomator进行定位
地址:https://developer.android.com/reference/android/support/test/uiautomator/UiSelector
优点:uiautomator是android自带的工作引擎,速度快
缺点:表达式书写复杂,容易写错而且没有提示
定位方式主要有
1、resource-id定位
new UiSelector().resourceId(“id”)
2、classname定位
new UiSelector().className(“className”)
3、content-desc定位
new UiSelector().description(“content-desc属性”)
4、通过文本定位
new UiSelector().text(“text文本”)
如果文本较长,可以用textContains模糊匹配
new UiSelector().textContains(“包含text文本”)
同样可以用textStartsWith是以某个文本开头来匹配
new UiSelector().textStartsWith(“以text文本开头”)
也可以用正则表达式textMatches匹配
new UiSelector().textMatches(“正则表达式”)
5、组合定位
例如
id与text属性组合
id_text=‘resourceId(“com.baidu.yuedu:id/title”).text(“新闻”)’
driver.find_element_by_android_uiautomator(id_text).click()
class与text属性结合
class_text=‘className(“android.widget.TextView”).text(”小米“)’
driver.find_element_by_android_uiautomator(class_text).click()
6、通过父子关系进行定位
有的时候某个元素不好定位,而它的父元素很好定位,这个时候我们可以先定位它的父元素,然后再去定位子元素
son=‘resourceId(“父元素”).childSelector(text(“子元素”))’
7、通过兄弟关系进行定位
有的时候父亲元素也不好定位,但是跟他相邻的元素却很好定位,这个时候我们可以根据兄弟元素找到同一父级元素下的子元素
bro=‘resourceId(“兄弟元素”).fromParent(text(“用户”))’
8、滚动查找元素
new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text(“要查找的文本”).instance(0))
总体来举个例子

import time

import pytest
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from appium.webdriver.common.touch_action import TouchAction


class TestDW():

  def setup(self):
    desire_caps = {
      "platformName": "android",
      "deviceName": "127.0.0.1:7555",
      "appPackage": "com.xueqiu.android",
      "appActivity": ".view.WelcomeActivityAlias",
        "noReset": "true",
      "unicodeKeyBoard" : "true",
      "resetKeyBoard" : "true"
    }
    self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_capabilities=desire_caps)
    self.driver.implicitly_wait(10)

  def teardown(self):
    self.driver.quit()

  def test_myinfomation(self):
    """
    1、打开雪球APP,进入到个人中心信息页面
    2、点击登录,进入到登陆页面
    3、输入用户名密码
    4、点击登录
    :return:
    """
    self.driver.find_element_by_android_uiautomator('new UiSelector().text("我的")').click()
    self.driver.find_element_by_android_uiautomator('new UiSelector().textContains("登录雪球")').click()
    self.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/login_account")').send_keys("123456")
    self.driver.find_element_by_android_uiautomator(
      'new UiSelector().resourceId("com.xueqiu.android:id/login_password")').send_keys("123456")
    time.sleep(2)
    self.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/button_next")').click()

  def test_scroll_find_element(self):
    self.driver.find_element_by_android_uiautomator('new UiSelector().text("关注")').click()
    self.driver.find_element_by_android_uiautomator('new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("似水年华").instance(0))').click()
    time.sleep(5)

举一个解锁操作的例子

  def test_touchaction_aunlock(self):
    print("让我们开始解锁操作吧")
    action = TouchAction(self.driver)
    action.press(x=243, y=395).wait(200).move_to(x=721, y=378).wait(200).move_to(x=1190, y=364).wait(200).move_to(x=1202, y=859).wait(200).move_to(x=1195, y=1339).wait(200).release().perform()
    print("完成解锁操作啦")

appium显示等待机制

我们之前说过,等待可以分为强制等待,全局隐式等待和显示等待;隐式等待我们可以理解为这是一个服务端的等待,而显示等待我们可以理解为是一个客户端的等待
显示等待必须在每个需要等待的元素前面进行声明;是针对某个特定的元素设置的等待时间,在设定时间内,默认每隔一段时间检测一次当前页面某个元素是否存在;如果在规定的时间内找到了元素,则直接执行,即找到元素就执行相关操作;如果超过设置时间检测不到则抛出异常,默认检测频率是0.5s,默认抛出的异常是No Such ElementExecption
显示等待用到的两个类:WebDriverWait和expectd_conditons两个类
显示等待可以动态的加载ajax元素,显示等待需要使用expectd_conditons来检查条件
一般页面上元素的呈现:
1、title出现
2、dom树出现,presence还不完整
3、css出现
4、js出现,js逻辑执行,也就是某些元素可以点击
所以对于某些元素,虽然他已经出现在了页面中,但是因为此时的js逻辑还没有加载出来,所以该元素还不能点击,因此我们需要用方法来检查我们这个元素是否此时是可以点击的
WebDriverWait用法
WebDriverWait(driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None)
driver:浏览器驱动
timeout:最长超时时间,默认以秒为单位
poll_frequency:检测的间隔时长,默认为0.5s
ignored_exceptions:超时后抛出的异常信息,默认抛出NoSuchElementExecption异常
WebDriverWait.until()和WebDriverWait.until_not()用法
until里面需要传入method和message=’'两个参数
method:在等待期间,每隔一段时间调用这个传入的方法,直到返回值不是False
message:如果超时,将message传入异常
until和until_not相反,until是当某个元素出现或什么条件成立则继续执行,until_not是当某个元素消失或什么条件不成立则继续执行,参数也相同

location =(mobileby.By.XPATH, "//*[@text='阿里巴巴-SW']")
WebDriverWait(self.driver, 10).until(expected_conditions.element_to_be_clickable(location))
self.driver.find_element_by_xpath(*location).click()

expected_conditions类中
presence_of_all_elements_located:判断元素是否被加到了dom树里,并不代表该元素一定可见
visibility_of_element_located:判断某个元素是否可见,可见代表元素非隐藏,并且元素的宽高都不等于0

toast控件识别

appium使用uiautomator底层的机制来分析抓取toast,并把toast放到控件树里面,但本身并不属于控件
必须使用xpath查找
//[@class=‘android.widget.Toast’]
//
[contains(@text, “XXXX”)]
举例:driver.find_element(MobileBy.xpath, “//*[contains(@text, ‘Clicked popup’)]”)

appium属性获取与断言

get_attribute原理分析
http://appium.io/docs/en/commands/element/attributes/attribute/
断言
普通断言,比如说用assert进行断言

  def test_get_current(self):
    """
    打开APP,点击搜索,输入阿里巴巴,判断阿里巴巴股票金额大于200
    """
    self.driver.find_element_by_id("com.xueqiu.android:id/home_search").click()
    print("001")
    print("002")
    self.driver.find_element_by_id("com.xueqiu.android:id/search_input_text").send_keys("阿里巴巴")
    print("003")
    print(self.driver.find_element_by_id("com.xueqiu.android:id/search_input_text").get_attribute("content-desc"))
    time.sleep(2)
    self.driver.find_element_by_xpath("//*[@text='阿里巴巴-SW']").click()
    print(self.driver.find_element_by_xpath("//*[@text='阿里巴巴-SW']").get_attribute('content-desc'))
    current_price = float(self.driver.find_element_by_xpath("//*[@text='09988']/../../..//*[@resource-id='com.xueqiu.android:id/current_price']").text)
    print(type(current_price))
    print(current_price)
    assert current_price>200

hamcrest地址:https://github.com/hamcrest/PyHamcrest
hamcrest是一个为了测试为目的,能组合成灵活表达式的匹配器类库,用于编写断言的框架,使用这个框架编写断言,提高可读性及开发测试的效率
hamcrest提供了大量被称为”匹配器“的方法,每个匹配器都设计用于执行特定的比较操作
hamcrest可扩展性强,让你能够创建自定义的匹配器,支持多种语言,java,python,ruby
在这里插入图片描述

from hamcrest import *
class Test_A():
    def test_hamrest(self):
        assert_that(10, equal_to(10))
        assert_that(8, close_to(10, 2))
        assert_that("contains some string", contains_string("string"))

appium参数化用例

我们也可以使用pytest的参数化功能,对我们的测试用例进行参数化,这个以前的贴子讲过,就不再具体展出讲述了
代码如下
在这里插入图片描述

appium设备交互api

appium提供了模拟复杂场景的测试用例,比如说
测试过程中模拟来电,来短信
模拟网络切换
运行过程中获取系统日志以及截图等功能

  def test_mobile(self):
    """
    模拟打电话发短信,设置网络类型以及获取截图
    :return:
    """
    self.driver.make_gsm_call('18810868807', GsmCallActions.CALL)
    self.driver.send_sms('18810903977', '你好,我是python')
    #设置网络类型
    self.driver.set_network_connection(1)
    time.sleep(3)
    self.driver.set_network_connection(2)
    #获取当前屏幕截图
    self.driver.get_screenshot_as_file('./photoes/img.png')

Capability的高级使用方法

Capability是我们在编写的脚本,包含我们发给服务器的运行设备的信息,具体可以查看如下网址:
http://appium.io/docs/en/writing-running-appium/caps/index.html
newCommandTimeout表示的是在多少秒内不会报异常,默认是60s
udid表示的多台设备的时候,可以对其中某一台进行自动化测试
autoGrantPermissions表示的是appium自动隐掉授权等弹窗,如果noReset is true,这个功能是不生效的
关于测试策略相关的:
noReset表示的是对APP不进行重置操作
fullreset表示会清除APP数据
dontStopAppOnRest表示的是不停止启动APP也就是我们在测试APP不同activity的时候,不杀掉APP进程
关于性能相关的
skipServerInstallation跳过server的安装
skipDeviceInitialization跳过设备的初始化
skipUnlock跳过解锁
skipLogcatCapture跳过日志的获取
ignoreUnimportantViews忽略掉不重要的组件
等等

android webview技术原理

使用命令appium -g appium2.log | tee启动appium,并且保存我们运行测试用例的结果
webview可以通过两种方式进行定位,一种是uiautomator,它能够将webview元素,解析成本地可以识别的元素,这种方式在不同的手机上结果是不一样的,另一种是通过chrome driver来完成请求的转发。
客户端和服务端进行连接需要建立共同的域套接字和相应的服务端的端口号,域套接字是进程与进程之间通讯的一种方式,真正的连接过程是套接字一直处于监听的状态,来监听客户端发来的请求,实际就是手机端会一直监听appiumserver发过来的请求;同时,appium会获取所有webview的进程并且查看进程的应用,启动chromedriver,将appiumserver的请求转发给chromedriver

appium源码分析

http://appium.io/docs/en/contributing-to-appium/appium-packages/
这里分为两大体系,一个是appium server
一个node.js开发的一系列的包,其中还包含有adb Chromedriver
appium源码:https://github.com/appium/appium
package.json——运行所依赖的包文件
主代码在lib文件下下
另一个是底层引擎
包含Uiautomator java、WDA、selenium
当然我们也可以对appium进行二次封装
修改后进行编译,编译过程可参考文档http://appium.io/docs/en/contributing-to-appium/appium-from-source/
然后进行构建,可以参考文档https://github.com/appium/appium-uiautomator2-server

企业微信APP为例用来自动化打卡功能

from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from appium.webdriver.common.touch_action import TouchAction


class TestWeChat():

  def setup(self):
    desire_caps = {
      "platformName": "android",
      "deviceName": "127.0.0.1:7555",
      "appPackage": "com.tencent.wework",
      "appActivity": "com.tencent.wework.launch.WwMainActivity",
        "noReset": "true",
      "unicodeKeyBoard" : "true",
      "resetKeyBoard" : "true"
    }
    self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_capabilities=desire_caps)
    self.driver.implicitly_wait(10)

  def teardown(self):
    self.driver.quit()

  def test_daka(self):
      """
      1、打开企业微信app
      2、点击“工作台”
      3、点击“打卡”
      4、点击“外出打卡”
      5、使用文本信息“次打卡”,点击
      6、判断打卡是否成功
      :return:
      """
      self.driver.find_element(MobileBy.XPATH, "//*[@text='工作台']").click()
      self.driver.find_element(MobileBy.ANDROID_UIAUTOMATOR, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("打卡").instance(0))').click()
      self.driver.find_element_by_id("com.tencent.wework:id/i1x").click()
      self.driver.find_element(MobileBy.XPATH, "//*[contains(@text,'次外出')]").click()
      result = self.driver.find_element(MobileBy.ID,"com.tencent.wework:id/pu").text
      assert '打卡成功' in result

运行结果:
在这里插入图片描述

标签:appium,需要,text,self,driver,element,自动化,android,APP
来源: https://blog.csdn.net/qq_41780297/article/details/114443416

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有