前言

Toast是什么呢?在这个手机飞速发展的时代,app的种类也越来越多,那们在日常生活使用中,经常会发现,当你在某个app的输入框输入非法字符或者非法执行某个流程时,经常看到系统会给你弹出一个黑色的提示框,告诉你你的操作不合法,比如某个app的登录流程,当你输入错误的用户名时,系统会弹出一个框提示你:用户名不正确,请重新输入;并且这个提示框往往会很快消失,并不需要用户自己执行关闭操作,其实这个弹框就是Toast

定位Toast的条件

定位toast及操作toast之前,你需要确保你的自动化测试环境应该满足以下条件

1.你的app自动化测试环境本身没有问题,能够成功执行自动化测试代码

2.appium server的版本应该在1.6以上(最好直接安装最新的版本,避免不必要的麻烦)

你可以参考我这篇关于appium环境搭建的文章,在写这篇文章时,我下载的就是比较老的版本,导致我后来定位toast时,一直定位不到,找了好半天原因,我一直以为我安装的是最新版的,其实并不是,罪魁祸首就是下载appim desktop时的地址不是官方的地址,当然之前的文章我也已经做了更新,避免你们遇到和我一样的问题

3.Toast是无法通过定位工具成功定位到的,所以你需要了解selenium中显示等待方法presence_of_element_located的作用(注意这里之只能使用这个方法,别的方法都无法定位到)

4.初始化driver时的参数需要指定automationName为UiAutomator2

Toast定位表达式

Toast虽然无法通过定位工具定位,但是几乎所有的toast都有一段文本,根据我们以往的经验,这段文本内容应该就是toast的text属性值,因此我们可以通过text属性结合xpath模糊定位的方式来定义toast的表达式,如果你对xpath有一定的了解,那么对这个表达式的意义应该不难理解: "//*[contains(@text, '{}')]".format("toast文本值")

需要说明一点,这里的@text代表的是toast的text属性(比如说它还有resource-Id属性),请区分web定位某一个元素时使用的定位表达式//*[contains(text(), '文本值')]

测试代码

定位表达式有了,再结合显示等待的presence_of_element_located方法,我们来编写一段测试代码测试一下是否能够成功定位到toast并获取他的文本值

"""
------------------------------------
@Time : 2019/8/12 20:28
@Auth : linux超
@File : test_toast.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ : 28174043@qq.com
@GROUP: 878565760
------------------------------------
"""
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.wait import WebDriverWait def wait_present_element(locator):
return WebDriverWait(driver, 20, 0.01).until(ec.presence_of_element_located(locator)) def wait_clickable_element(locator):
return WebDriverWait(driver, 20, 0.01).until(ec.element_to_be_clickable(locator)) desired_caps = {
"automationName": "UiAutomator2",
"platformName": "Android",
"platformVersion": "5.1.1",
"deviceName": "127.0.0.1:62001",
"appPackage": "com.xxzb.fenwoo",
"appActivity": "com.xxzb.fenwoo.activity.addition.WelcomeActivity"
}
# 初始化driver
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
# 直接跳到指定页面
driver.start_activity("com.xxzb.fenwoo", ".activity.addition.FillPhoneActivity")
# 输入用户名
wait_present_element((MobileBy.ID, "com.xxzb.fenwoo:id/et_phone")).send_keys("")
# 点击下一步
wait_present_element((MobileBy.ID, "com.xxzb.fenwoo:id/btn_next_step")).click()
# 定位toast
toast = wait_present_element((MobileBy.XPATH, "//*[contains(@text, '{}')]".format('无效的手机号码')))
# 获取toast的文本值
# context = toast.text
context = toast.get_attribute("text")
print("toast的文本值为", context)
# 关闭driver
driver.quit()

输出

toast的文本值为无效的手机号码

Process finished with exit code 0

ok, 这段代码成功输出了toast的文本值,那么在自动化测试的时候,我们就可以通过文本值来做一些断言了

代码优化

你会发现上面的测试代码完全是流水式的编程方式,实际工作中几乎不会允许你出现这样的代码,虽然今天的主题是如何处理toast,无关代码写的好与不好,也无关代码的编程思想,但是我想说的是所有的代码书写规范和编程思想都是日积月累的养成的,并不是一朝一夕就能掌握的,而且我也希望看到我文章的人不仅仅只学到简单的用法,除此之外还能学到一些编程思想和小技巧,还是那句话希望在你成功的道路上有我的身影!

废话说了这么多,我们需要做的就是模块化,把一些代码中能够分离出来的部分,能够重复调用的部分进行分离,比如查找某一个元素,等待某个元素能点击,等待某个元素出现,向某个输入框中输入值等,还有就是把所有的操作尽量结合显示等待来操作,这样可以增加脚本的稳定性,并且对于toast的定位我们也需要封装成一个通用的方法,通过传递不同的文本值,达到定位不同toast的目的

封装代码

"""
------------------------------------
@Time : 2019/8/12 8:45
@Auth : linux超
@File : base.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ : 28174043@qq.com
@GROUP: 878565760
------------------------------------
"""
from appium.webdriver import WebElement
from appium.webdriver.common.mobileby import MobileBy
from appium.webdriver.webdriver import WebDriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common.exceptions import TimeoutException, NoSuchElementException
from selenium.webdriver.support import expected_conditions as ec class Base(object): def __init__(self, driver: WebDriver):
self.driver = driver def find_element(self, locator: tuple, timeout=30) -> WebElement:
wait = WebDriverWait(self.driver, timeout)
try:
element = wait.until(lambda driver: driver.find_element(*locator))
return element
except TimeoutException as e:
print('no found element {} by {}'.format(locator[1], locator[0]))
raise e def input_value(self, locator: tuple, value):
element = self.find_element(locator)
if element:
element.clear()
return element.send_keys(value)
else:
raise NoSuchElementException("the element not found, so doesn't input value") def wait_element_presence(self, locator, timeout=30) ->WebElement:
"""等待元素出现在DOM中,但是不一定是可见的"""
wait = WebDriverWait(self.driver, timeout, 0.01)
try:
element = wait.until(ec.presence_of_element_located(locator))
return element
except TimeoutException as e:
print("the element {} not presence".format(locator[1]))
raise e def wait_element_clickable(self, locator: tuple, timeout=30):
wait = WebDriverWait(self.driver, timeout)
try:
element = wait.until(ec.element_to_be_clickable(locator))
return element
except TimeoutException as e:
print("the element {} not found or element un-clickable".format(locator[1]))
raise e def click(self, locator: tuple):
element = self.wait_element_clickable(locator)
if element:
return element.click()
else:
raise TypeError('NoneType object is not callable') def get_toast(self, context):
"""text: toast的文本值
只支持appium server 版本在1.6以上,且"automationName"为"uiautomator2"
"""
locator = (MobileBy.XPATH, "//*[@text='{}']".format(context))
toast = self.wait_element_presence(locator)
try:
try:
text = toast.text
except AttributeError:
text = toast.get_attribute("text")
except AttributeError as e:
print("get context of toast fail")
raise e
return text if __name__ == '__main__':
pass

测试代码

"""
------------------------------------
@Time : 2019/8/12 21:10
@Auth : linux超
@File : toast.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ : 28174043@qq.com
@GROUP: 878565760
------------------------------------
"""
import unittest
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy from base import Base class TestToast(unittest.TestCase): phone_element = (MobileBy.ID, "com.xxzb.fenwoo:id/et_phone")
next_setup = (MobileBy.ID, "com.xxzb.fenwoo:id/btn_next_step") def setUp(self):
desired_caps = {
"automationName": "UiAutomator2",
"platformName": "Android",
"platformVersion": "5.1.1",
"deviceName": "Android Emulator",
"appPackage": "com.xxzb.fenwoo",
"appActivity": "com.xxzb.fenwoo.activity.addition.WelcomeActivity",
"noReset": "true"
}
self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps) def test_toast(self):
base = Base(self.driver)
self.driver.start_activity("com.xxzb.fenwoo", ".activity.addition.FillPhoneActivity")
base.input_value(self.phone_element, '')
base.click(self.next_setup)
toast_text = base.get_toast("无效的手机号码")
print(toast_text)
self.assertEqual("无效的手机号码", toast_text)
def tearDown(self): 
self.driver.quit() if __name__ == '__main__':
unittest.main()

封装代码中的toast方法,有一点需要说明,通过WebElement.text的方式并不一定能够获取到它的文本值,所以根据以往的经验通过get_attribute("属性")应该就能获取到了

执行过程及测试结果

如何获取app中的toast的更多相关文章

  1. 解压Assets.car获取App中的图片资源

    iOS开发时图片资源(png)是放置在Images.xcassets文件夹中进行管理的. 项目归档后就是ipa文件,在ipa文件中,Images.xcassets文件夹的内容放置在了Assets.ca ...

  2. iOS获取app图标和启动图片名字(AppIcon and LaunchImage's name)

    在某种场景下,可能我们需要获取app的图标名称和启动图片的名称.比如说app在前台时,收到了远程通知但是通知栏是不会有通知提醒的,这时我想做个模拟通知提示,需要用到icon名称:再比如在加载某个控制器 ...

  3. iOS从健康app中获取步数信息

    统计步数信息并不需要我们自己去实现,iOS自带的健康app已经为我们统计好了步数数据 我们只要使用HealthKit框架从健康app中获取这个数据信息就可以了 1.如下图所示 在Xcode中打开Hea ...

  4. iOS利用HealthKit框架从健康app中获取步数信息

    微信和QQ的每日步数最近十分火爆,我就想为自己写的项目中添加一个显示每日步数的功能,上网一搜好像并有相关的详细资料,自己动手丰衣足食. 统计步数信息并不需要我们自己去实现,iOS自带的健康app已经为 ...

  5. app中获取应用名称,版本等信息的方法

    在app中,我们有时候需要显示一些信息,例如名称,版本等等...如果用写死的方式可能不太好,我们可以动态的读取.应用的信息主要是在info.plist这个文件中,实际就是一个xml文件,以源文件的方式 ...

  6. 如需在APP中使用腾讯QQ登陆,需提前申请获取腾讯QQ的APPKEY和APPSecret。

    如需在APP中使用腾讯QQ登陆,需提前申请获取腾讯QQ的APPKEY和APPSecret. 申请流程如下: 步骤1:登陆腾讯开放平台.链接地址: http://open.qq.com/ . 步骤2:填 ...

  7. MFC中获取App,MainFrame,Doc和View类等指针的方法

    From: http://hi.baidu.com/wxnxs/item/156a68f5b3b4ed18e3e3bd03   MFC中获取App,MainFrame,Doc和View类等指针的方法 ...

  8. 小程序中关于获取app实例与当前组件

    1.getApp()来获取 App 实例 2.getCurrentPages()获取前页面栈

  9. Win 10 开发中Adaptive磁贴模板的XML文档结构,Win10 应用开发中自适应Toast通知的XML文档结构

    分享两篇Win 10应用开发的XML文档结构:Win 10 开发中Adaptive磁贴模板的XML文档结构,Win10 应用开发中自适应Toast通知的XML文档结构. Win 10 开发中Adapt ...

随机推荐

  1. 『开发技巧』Keras自定义对象(层、评价函数与损失)

    1.自定义层 对于简单.无状态的自定义操作,你也许可以通过 layers.core.Lambda 层来实现.但是对于那些包含了可训练权重的自定义层,你应该自己实现这种层. 这是一个 Keras2.0  ...

  2. MYSQL手工注入(详细步骤)—— 待补充

    0x00 SQL注入的分类: (1)基于从服务器接收到的响应         ▲基于错误的 SQL 注入         ▲联合查询的类型         ▲堆查询注射         ▲SQL 盲注 ...

  3. C#实现某一属性值变化时触发事件

    在我们做工业软件中,经常会遇到要实时监控某一点,在这个点变化时去做一些事情 放入程序里呢,就是要实时监控某一属性的值,当值发生变化时触发事件,其核心就是借助属性的Set方法,来判断当前set的值是否与 ...

  4. MMM 状压dp学习记

    状压dp学习记 by scmmm 开始日期 2019/7/17 前言 状压dp感觉很好理解(本质接近于爆搜但是又有广搜的感觉),综合了dp的高效性(至少比dfs,bfs优),又能解决普通dp难搞定的问 ...

  5. springcloud入门系列

    关于springcloud 1.写在前面 写着写这,不知不觉springcloud写了7,8篇了,今天把文章分下类,写下感受及后面的计划吧. (1)springcloud中最最重要的是eureka注册 ...

  6. 深度解密Go语言之channel

    目录 并发模型 并发与并行 什么是 CSP 什么是 channel channel 实现 CSP 为什么要 channel channel 实现原理 数据结构 创建 接收 发送 关闭 channel ...

  7. 百度OCR文字识别API使用心得===com.baidu.ocr.sdk.exception.SDKError[283604]

    异常com.baidu.ocr.sdk.exception.SDKError[283604]App identifier unmatch.错误的packname或bundleId.logId::303 ...

  8. Linux基础学习整理

    linux学习记录 下载地址 centos 下载地址: 网易镜像:http://mirrors.163.com/centos/6/isos/ 搜狐镜像:http://mirrors.sohu.com/ ...

  9. hdu6375 度度熊学队列

    度度熊学队列 题目传送门 解题思路 STL大法好.直接用deque,但是N的范围很大,如果直接开那么多的deque会爆内存,所以用map< int, deque< int>>, ...

  10. Linnux命令大全(vim)

    vim复制和粘贴的基本命令(注:需先退出编辑模式)    yy复制游标所在行整行.或大写一个Y. (常用)    2yy或y2y复制两行. (常用)    y^复制至行首,或y0.不含游标所在处字元. ...