软件测试/测试开发丨App自动化测试学习笔记分享

本文为霍格沃兹测试开发学社学员学习笔记分享

原文链接:https://ceshiren.com/t/topic/25599

App 自动化测试的价值与体系

  • 提高效率

    • 融入企业迭代流水线,与 CI/CD/DevOps 结合
    • 回归测试、功能测试加速
  • 提高质量:

    • 兼容性测试
    • 专项/非功能测试
    • 自动化探索测试

UI 自动化测试用例如何编写

  • 业务流程不频繁改动
  • UI 元素不频繁改动
  • 需要频繁回归的场景
  • 核心场景等

环境安装与使用

什么是appium

  • Client/Server Architecture:c/s 架构

  • 脚本多语言支持

    • Java、Python、ruby、PHP、JavaScript、C#
  • 生态丰富,社区强大

Android 命令行工具

  • 管理移动端设备上应用程序的安装与卸载,以及查看相关信息

  • adb

    • 安卓系统的命令行控制工具
    • 获取安卓端的各种数据和控制
    • sdk 自带工具
adb devices #显示当前所连接设备的udid

iOS 命令行工具

  • ideviceinstaller

    • iOS 系统的命令行控制工具
    • 获取 iOS 端的各种数据和控制
idevice_id -l #显示当前所连接设备的 udid

Appium Desktop

  • 内嵌了 Appium Server

  • Appium Server GUI

    • Appium 核心工具,命令行工具
  • Appium Inspector

    • 1.22 版本后,和 desktop 分开

Appium Client

  • 各种语言的客户端封装库、用于连接 Appium Server

capability 配置参数解析

简介:

  • 功能:配置 Appium 会话,告诉 Appium 服务器需要自动化的平台的应用程序

  • 形式:键值对的集合,键对应设置的名称,值对应设置的值

  • 主要分为三部分

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

Session:

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

配置优化

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

app 自动化控制

  • 启动应用
  • 方式一:webdriver.remote("url",desirecapability)
  • 方式二:launch_app() 将应用启动起来
# 方式一:
self.driver = webdriver.Remote\
("http://127.0.0.1:4723/wd/hub", desire_cap)

# 方式二:
self.driver.launch_app()
  • 清空输入框内容 clear()
self.driver.find_element_by_accessibility_id('SomeAccessibilityID').clear()
  • 关闭 quit()
self.driver.quit()

常见控件定位方法

android 基础知识

  • Android 是通过容器的布局属性来管理子控件的位置关系,布局关系就是把界面上的所有的空间,根据他们的间距的大小,摆放在正确的位置

  • Android 七大布局

    • LinerLayout(线性布局)
    • RelativeLayout(相对布局)
    • FrameLayout(帧布局)
    • AboluteLayout(绝对布局)
    • TableLayout(表格布局)
    • GridLayout(网格布局)
    • ConstraintLayout(约束布局)
  • Android 四大组件

    • activity 与用户交互的可视化界面
    • service 实现程序后台运行的解决方案
    • content provider 内容提供者,提供程序所需要的数据
    • broadcast receiver 广播接收器,监听外部事件的到来(比如来电)
  • 常用的控件

    • TextView(文本控件),EditText(可编辑文本控件)
    • Button(按钮),ImageButton(图片按钮),ToggleButton(开关按钮)
    • ImageView(图片控件)
    • CheckBox(复选框控件),RadioButton(单选框控件)
  • 布局

    • 是可用于放置很多控件的容器按照一定的规律调整内部控件的位置由此构成界面。
  • 嵌套布局

    • 布局内部放置布局,多层布局嵌套,可以完成复杂的界面结构

iOS 与 Android dom 结构的区别

  • dom 属性和节点结构类似

  • 名字和属性命名不同

    • android 的 resourceid 和 ios 的 name
    • android 的 content-desc 和 ios 的 accessibility-id

定位方法

  • 测试步骤三要素

    • 定位、交互、断言
  • 定位方式:

    • id 定位
    • accessibilty_id 定位
    • xpath 定位
    • classname 定位(不推荐)

元素定位的写法

  • 返回单个元素 WebElement
  • 返回元素列表 [WebElement, WebElement, WebElement…]
# 返回单个元素 WebElement
driver.find_element(AppiumBy.xxx, "xxx属性值")
# 返回元素列表 [WebElement, WebElement, WebElement...]
driver.find_elements(AppiumBy.xxx, "xxx属性值")

元素定位的写法

driver.find_element(AppiumBy.ID, "ID属性值")
driver.find_element(AppiumBy.XPATH, "xpath表达式")
driver.find_element(AppiumBy.CLASS_NAME, "CLASS属性值")
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "ACCESSIBILITY_ID表达式")
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, "android uiautomator 表达式")
driver.find_element(AppiumBy.IOS_UIAUTOMATION, "ios uiautomation 表达式")
driver.find_element(AppiumBy.ANDROID_VIEWTAG, "ESPRESSO viewtag 表达式")
driver.find_element(AppiumBy.ANDROID_DATA_MATCHER, "ESPRESSO data matcher 表达式")
driver.find_element(AppiumBy.IMAGE, "IMAGE图片")

ID 定位

  • 通过身份标识 id 查找元素
  • 写法:find_element(AppiumBy.ID, "ID属性值")

ACCESSIBILITY_ID 定位

  • 通过 accessibility id 查找元素
  • 写法:find_element(AppiumBy.ACCESSIBILITY_ID, "ACCESSIBILITY_ID属性值")

XPath 单属性定位

  • 基本表达式://*[@属性名='属性值']

XPath 多属性定位

  • 表达式://*[@属性名='属性值' and @属性名='属性值' ]

Android 原生定位

  • 元素属性定位
  • ID 定位
  • 文本定位
  • 文本匹配定位
  • 父子关系定位
  • 兄弟关系定位

Android 原生定位 - 单属性定位

  • 格式 'new UiSelector().属性名("<属性值>")'

    • 比如:'new UiSelector().resourceId("android:id/text1")'
  • 注意外面是单引号,里面是双引号,顺序不能变

  • 可以简写为 属性名("<属性值>")'

    • 比如:·resourceId("android:id/text1")
# ID 定位
def test_android_uiautomator_by_id(self):   
        print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,\
                'new UiSelector().resourceId("android:id/text1")'))
# TEXT 定位
def test_android_uiautomator_by_text(self):
        print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,\
                'new UiSelector().text("App")'))

# classname 定位
def test_android_uiautomator_by_className(self):   
        print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, \
                'new UiSelector().className("android.widget.TextView")'))
Android 原生定位-组合定位
多个属性同时确定元素的(多个属性任意组合 ,不限长度)
driver.find_element_by_android_uiautomator('\
    new UiSelector().resourceId("com.xueqiu.android:id/tab_name").\
    text("我的")')
Android 原生定位-模糊匹配
文字包含
文字以 x 开头
文字正则匹配
# 模糊匹配
def test_android_uiautomator_by_text_contains(self):
    print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().textContains("ssi")').text)

def test_android_uiautomator_by_text_start_with(self):
    print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().textStartsWith("Ani")').text)

def test_android_uiautomator_by_text_match(self):
    print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().textMatches("^Pre.*")').text)
Android 原生定位-层级定位
兄弟元素定位 fromParent
父子结点定位 childSelector, 可以传入 resourceId() , description() 等方法
# 查找目标元素Text,先找App ,fromParent() 方法可以查找兄弟结点
new UiSelector().text("App").fromParent(text("Text"))

# 根据父结点查找子结点/ 子孙结点
new UiSelector().className("android.widget.ListView").childSelector(text("Text"))
滑动查找元素
new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("查找的元素文本").instance(0))

Android 原生定位-组合定位

  • 多个属性同时确定元素的(多个属性任意组合 ,不限长度)
driver.find_element_by_android_uiautomator('\
    new UiSelector().resourceId("com.xueqiu.android:id/tab_name").\
    text("我的")')

Android 原生定位-模糊匹配

  • 文字包含
  • 文字以 x 开头
  • 文字正则匹配

Android 原生定位-层级定位

  • 兄弟元素定位 fromParent
  • 父子结点定位 childSelector, 可以传入 resourceId() , description() 等方法

滑动查找元素

new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().t
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值