【App自动化测试】(十)特殊控件Toast识别

news2025/7/24 5:57:47

目录

  • 1. toast介绍
  • 2. toast定位
  • 3. 实例演示


前言
本文为在霍格沃兹测试开发学社中学习到的一些技术写出来分享给大家,希望有志同道合的小伙伴可以一起交流技术,一起进步~ 😘

1. toast介绍

  • Toast,简易的消息提示框。
  • 为了给当前视图显示一个浮动的显示块,与dialog不同它永远不会获得焦点。
  • Toast类的思想:尽可能不引人注意,同时还向用户显示信息希望他们看到。
  • Toast显示的时间有限,Toast会根据用户设置的显示时问后自动消失。
  • Toast本身是个系统级别的控件,它归属于系统settings,当一个app发送消息的时候,不是自己造出来的这个弹框,它是发给系统,由系统统一进行弹框,这类的控件不在app内,需要特殊的控件识别方法。

2. toast定位

在这里插入图片描述

  • appium使用uiautomator底层的机制来分析抓取toast,并且把toast放到控件树里面,但是它本身并不属于空间。

    private void addToastMsgToRoot(CharSequence tokenMSG){
      AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain( );
      node.setText(tokenMSG);
      node.setclassName(Toast.class.getName( ) ) ;
      node.setPackageName( " com.android.settings"" ) ;
    
    this.children.add( new UiAutomationElement(node /* Accessibility)
    }
    
  • 必须使用xpath来查找:

    1. class定位: //*[@class='android.widget.Toast']
      注:一般不建议使用class来进行定位,但是Toast是个例外,一般只会有一个Toast的class,所以可以使用
    2. 文本内容定位: //*[contains(@text,"XXX")] (XXX是tosat信息中的部分内容)

3. 实例演示

测试程序:APIDemos

测试内容:直接进入View下面的Pop menu 界面,然后点击操作按钮产生toast,并进行断言。

步骤

  1. 先获取当前页面的Activity

由于我们使用APIDemos来进行测试,所以可以跳过前面的步骤,直接打开我们要使用的Pop menu 界面去进行操作。但是正常app测试是无法这样操作的。

运行命令:

#iOS和Linu系统
adb shell dumpsys window | grep mCurrent

#Windows系统
adb shell dumpsys window | find "mCurrent"

在这里插入图片描述

  1. 由于Toast无法使用定位工具直接去定位,如Appium Inspector,所以我们可以打印出PageSource,然后在去对Toast进行属性的查看
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy

class TestToast:
    def setup(self):
        #io.appium.android.apis/.ApiDemos
        # 创建一个字典
        desire_cap = {}
        # 平台
        desire_cap['platform'] = 'Android'
        # 手机系统版本
        desire_cap['platformVersion'] = '6.0'
        # 设备名
        desire_cap['deviceName'] = '127.0.0.1:7555'
        # app 包名
        desire_cap['appPackage'] = 'io.appium.android.apis'
        # app 页面名
        desire_cap['appActivity'] = '.view.PopupMenu1'
        desire_cap['noReset'] = 'true'
        self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desire_cap)
        self.driver.implicitly_wait(10)

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

    def test_toast(self):
        #点击 Make a Popup!
        self.driver.find_element(AppiumBy.ACCESSIBILITY_ID,"Make a Popup!").click()
        #点击 点击search
        self.driver.find_element(AppiumBy.CSS_SELECTOR, "*[text='Search']").click()
        #打印pagesource
        print(self.driver.page_source)

PageSource内容:通过PageSource可以知道,此处Toast的class属性为"android.widget.Toast",它的text属性为"Clicked popup menu item Search"。

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<hierarchy index="0" class="hierarchy" rotation="3" width="900" height="1600">
  <android.widget.FrameLayout index="0" package="io.appium.android.apis" class="android.widget.FrameLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,0][900,1600]" displayed="true">
    <android.view.ViewGroup index="0" package="io.appium.android.apis" class="android.view.ViewGroup" text="" resource-id="android:id/decor_content_parent" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,0][900,1600]" displayed="true">
      <android.widget.FrameLayout index="0" package="io.appium.android.apis" class="android.widget.FrameLayout" text="" resource-id="android:id/action_bar_container" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,45][900,150]" displayed="true">
        <android.view.ViewGroup index="0" package="io.appium.android.apis" class="android.view.ViewGroup" text="" resource-id="android:id/action_bar" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,45][900,150]" displayed="true">
          <android.widget.TextView index="0" package="io.appium.android.apis" class="android.widget.TextView" text="Views/Popup Menu" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[30,71][361,123]" displayed="true" />
        </android.view.ViewGroup>
      </android.widget.FrameLayout>
      <android.widget.FrameLayout index="1" package="io.appium.android.apis" class="android.widget.FrameLayout" text="" resource-id="android:id/content" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,150][900,1600]" displayed="true">
        <android.widget.LinearLayout index="0" package="io.appium.android.apis" class="android.widget.LinearLayout" text="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,150][900,1600]" displayed="true">
          <android.widget.Button index="0" package="io.appium.android.apis" class="android.widget.Button" text="Make a Popup!" content-desc="Make a Popup!" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[331,150][568,240]" displayed="true" />
        </android.widget.LinearLayout>
      </android.widget.FrameLayout>
    </android.view.ViewGroup>
  </android.widget.FrameLayout>
  <android.widget.Toast index="1" package="com.android.settings" class="android.widget.Toast" text="Clicked popup menu item Search" displayed="true" />
</hierarchy>

  1. 定位方式一:通过class属性进行定位

一般一个页面只用一个toast类,因此可以使用class属性定位

from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy

class TestToast:
    def setup(self):
        #io.appium.android.apis/.ApiDemos
        # 创建一个字典
        desire_cap = {}
        # 平台
        desire_cap['platform'] = 'Android'
        # 手机系统版本
        desire_cap['platformVersion'] = '6.0'
        # 设备名
        desire_cap['deviceName'] = '127.0.0.1:7555'
        # app 包名
        desire_cap['appPackage'] = 'io.appium.android.apis'
        # app 页面名
        desire_cap['appActivity'] = '.view.PopupMenu1'
        self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desire_cap)
        self.driver.implicitly_wait(10)

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

    def test_toast(self):
        #点击 Make a Popup!
        self.driver.find_element(AppiumBy.ACCESSIBILITY_ID,"Make a Popup!").click()
        #点击 点击search
        self.driver.find_element(AppiumBy.CSS_SELECTOR, "*[text='Search']").click()
	#通过class属性定位Toast
        toast=self.driver.find_element(AppiumBy.XPATH,'//*[@class="android.widget.Toast"]')
        assert "Clicked popup menu item Search"==toast.text
  1. 定位方式二:通过toast展现的文字进行定位

使用contains方式,通过toas的text属性去模糊匹配其中的内容,从而完成Toast的定位。

from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy

class TestToast:
    def setup(self):
        #io.appium.android.apis/.ApiDemos
        # 创建一个字典
        desire_cap = {}
        # 平台
        desire_cap['platform'] = 'Android'
        # 手机系统版本
        desire_cap['platformVersion'] = '6.0'
        # 设备名
        desire_cap['deviceName'] = '127.0.0.1:7555'
        # app 包名
        desire_cap['appPackage'] = 'io.appium.android.apis'
        # app 页面名
        desire_cap['appActivity'] = '.view.PopupMenu1'
        self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desire_cap)
        self.driver.implicitly_wait(10)

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

    def test_toast(self):
        #点击 Make a Popup!
        self.driver.find_element(AppiumBy.ACCESSIBILITY_ID,"Make a Popup!").click()
        #点击 点击search
        self.driver.find_element(AppiumBy.CSS_SELECTOR, "*[text='Search']").click()
	#模糊匹配Toast中的Text属性的文本内容,完成Toast的定位
        toast=self.driver.find_element(AppiumBy.XPATH,'//*[contains(@text,"Clicked popup")]')
        assert "Clicked popup menu item Search"==toast.text

文末说明:
接口测试中我们很容易混淆Session、cookie和token,你知道他们有什么区别吗?

快来跟我一起看,一篇文章让你了解三者的区别。😎
⬇⬇⬇⬇⬇⬇⬇
👍👍👍:接口测试经典面试题:Session、cookie、token有什么区别?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/35452.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CANdelaStudio-从入门到深入目录

前文介绍诊断协议那些事儿专栏,为大家深入介绍了ISO 14229各个服务的基础知识、请求与响应的报文格式,详情可查看:诊断协议那些事儿,从本专题开始,将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希…

HTML5学习笔记(四)

CSS3 颜色样式 在CSS3中&#xff0c;增加了大量定义颜色方面样式的属性&#xff0c;主要包括以下3种。 ▶ opacity透明度 ▶ RGBA颜色 ▶ CSS3渐变 opacity透明度 opacity属性取值是一个数值&#xff0c;取值范围为0.0~1.0。其中0.0表示完全透明&#xff0c;1.0表示完全不透…

I/O模型

网络IO的本质 网络IO的本质就是socket流的读取&#xff0c;通常一次IO读取会涉及两个阶段与两个对象&#xff0c;其中两个对象为&#xff1a;用户进程&#xff08;线程&#xff09;Process&#xff08;Thread&#xff09;、内核对象&#xff08;kernel&#xff09;,两个阶段为…

北方地区长乐市污水厂(150000m3d)工艺设计

目 录 1设计说明书 3 1.1概述 3 1.1.1设计题目 3 1.1.2设计任务 3 1.1.3设计阶段&#xff08;设计程度&#xff09; 3 1.1.4设计依据 3 1.1.5设计原始资料 3 1.1.6设计工作量 5 1.1.7设计要求 5 1.1.8 毕业设计日期 5 1.2 设计要求 6 1.2.1 设计原则 6 1.2.3 设计内容 6 1.3 水…

PLC中ST编程的比较运算

比较运算符&#xff1a; >大于、 <小于、 >大于等于、 <小于等于、等于、 <>不等于。 BOOL类型的比较是通过1&#xff08;TRUE&#xff09;和0&#xff08;FALSE&#xff09;来比较的&#xff1b; 只有xIn_1为真&#xff0c;xIn_2为假的时候&#xff0c;xRe…

《小猫猫大课堂》1——小喵是如何开启敲代码之路的?

更新不易&#xff0c;麻烦多多点赞&#xff0c;欢迎你的提问&#xff0c;感谢你的转发&#xff0c; 最后的最后&#xff0c;关注我&#xff0c;关注我&#xff0c;关注我&#xff0c;你会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真…

【Vue基础系列】vue-router 万字详解,一篇彻底搞懂

目录 一、路由的简介 二、路由基本使用 三、嵌套路由 四、路由的query参数 五、路由的params参数 六、路由的props配置 七、编程式路由导航 八、缓存路由组件 九、两个新的生命周期钩子 十、路由守卫 一、路由的简介 我们在生活中经常听到路由器&#xff0c;但关于路由…

将项目部署至云服务器的详细过程 以community项目为例

文章目录1.申请一个2核4G的云服务器&#xff0c;系统选择CentOS 7.62.使用终端连接云服务器3.使用 wget 命令下载以下安装文件4.安装jdk125.安装maven6.安装MySQL7.初始化mysql数据库8.安装Redis9.安装kafka10.安装elasticsearch及其分词工具11.安装Wkhtmltopdf12.安装tomcat13…

【Spring框架】一文带你吃透基于注解的DI技术详细教程

本文目录 文章目录本文目录&#x1f496;基于注解的DI✨概念✨[Component](https://so.csdn.net/so/search?qComponent&spm1001.2101.3001.7020)注解创建对象✨声明组件扫描器✨创建对象的四个注解✨扫描多个包的三种方式✨Value简单类型属性赋值✨Value使用外部属性配置文…

外卖项目07---git

git&#xff1a;企业、公司等 目录 一、Git概述 105 1.1Git简介 105 1.2Git下载与安装 105 二、Git代码托管服务 106 2.1常用的Git代码托管服务 106 三、Git常用命令 107 3.1Git全局配置 3.2获取Git仓库 ​编辑 ​编辑 3.3工作区、暂存区、版本库概念 3.4Git工作…

ASPICE系列:顺利通过ASPICE流程软件单元验证(SWE.4)

上次的ASPICE评估是否出了问题而您不知道原因? 或者您马上要进行第一次评估&#xff1f; 本系列文章是关于如何准备ASPICE流程软件单元验证(SWE.4)评估的。我们探究这个过程&#xff0c;预期交付以及评估人员的观点。永远记住一个想法:怎样做才能成功地通过评估? 想要成功通…

【PdgCntEditor】利用PDF目录书签编辑软件PdgCntEditor为PDF型图书快速添加书签的方法

一、给PDF加书签的两种情况 1.1 文字版PDF添加书签的理想情形 假设我们弄到了一本PDF&#xff0c;这个PDF如果是由Word或WPS转化而来&#xff0c;其中的标题也就代表了目录&#xff0c;我们可以用acrobat PDF中的AutuBookmark插件实现自动识别标题为目录的方法来添加书签。 …

『Java安全』利用反射调用MimeLauncher.run()触发RCE

文章目录前言MimeLauncherrun()MimeLauncher()反射调用MimeLauncher.run()触发RCE条件PoC完前言 rt.jar内的sun.net.www.MimeLauncher类的run方法调用了exec 据说可以有效绕过某些免杀&#xff0c;下面分析一下调用过程 MimeLauncher run() 首先&#xff1a;调用了this.m.ge…

古人的名与字、号、讳、谥有什么区别

古人复杂的名字 这个世界上想来是不存在没有名字的人&#xff0c;即便真的有人没名字&#xff0c;也会被外人赠予姓名&#xff0c;比如说一些古人典籍里的“无名氏”&#xff0c;就是专门用来形容那些没有名字也不清楚根脚的人&#xff0c;即便是现如今一些作品不知道作者是谁…

信号与线性时不变系统的傅里叶描述

1、复正弦信号和线性时不变系统的频率相应 卷积积分和卷积和傅里叶变换冲激表示信号正弦表示信号输入信号表示为延迟冲激的加权叠加输入信号为复正弦信号的加权叠加输出可以用卷积的形式来表示输出可以用傅里叶的形式来表示 (1)频率响应Frequency response 线性时不变系统对正…

Java中mybatis的Mpper代理开发的详细使用步骤

目录 前言&#xff1a; 一、全图预览 二、使用步骤 1.pom.xml里面添加依赖包 2.新建统一配置文件&#xff08;俗称数据库连接文件&#xff09; 3.新建项目 4.新建映射文件&#xff08;俗称数据库对应表xml&#xff09; 5.测试 三、文中的全部代码&#xff08;去复制可…

MySQL如何保证主备一致?

1. MySQL主备的基本原理 如下图展示的是基本的主备切换流程&#xff1a; 在状态1中&#xff0c;主库是A&#xff0c;备库是B&#xff0c;所以客户端的读写都直接方法节点A。由于节点B是节点A的备库&#xff0c;所以备库B只是将A的更新都同步过来&#xff0c;本地执行&#x…

皕杰报表使用字体和部署后添加字体

Windows系统 1、打开Win10系统的字体安装文件夹&#xff0c;可以双击打开此电脑-->打开C盘-->打开Windows-->打开Fonts&#xff1b;也可先打开计算机&#xff0c;在计算机地址栏上直接拷贝“C:WindowsFonts”路径。回车打开Win10字体文件夹。 2.下载自己需要的字体。…

数组、链表、栈、队列、树

1. 数组&#xff08;Array&#xff09; 定义&#xff1a;数组是一种 线性表 数据结构&#xff0c;它用一组 连续的内存空间 存储一组具有 相同类型 的数据。 Java中 基本数据类型数组 的存储格式&#xff1a; int arr[] new int[3]; arr[0] 0; arr[1] 1; arr[2] 2;Java中…

拿去吧你,华为出品《看漫画学Python》零基础自学首选~

目前Python在人工智能、机器学习、大数据、数据分析、网络爬虫等领域广泛应用&#xff0c;是非常适合初学者入门和培养编程兴趣的一门语言。相比较其他主流编程语言而言&#xff0c;有更好的可读性&#xff0c;和满足感&#xff0c;上手相对容易。 但是很多零基础的同学不知道…