前言

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. scrapy基础知识之scrapy自动下载图片pipelines

    需要在settings.py配置: ITEM_PIPELINES = { 'scrapy.pipelines.images.ImagesPipeline': 1, }import os IMAGES_ ...

  2. php中对象类型与数组之间的转换

    1.刚看视频学习的时候看到一个困扰很久的问题, 有时候我们在进行做项目的时候会碰到的一个小问题.举一个小例子.  获取一个xml文件里面的数据. xml.xml文件如下: <?xml versi ...

  3. 使用PowerShell比较本地文本文件与Web上的文本文件是否相同

    使用PowerShell比较本地文本文件是否相同通常有两种方式:1.通过Get-FileHash这个命令,比较两个文件的哈希是否相同:2.通过Compare-Object这个命令,逐行比较两个文件的内 ...

  4. RSYNC部署

    1 rsync简介 1.1 什么是rsync rsync: - a fast, versatile, remote (and local) file-copying toolrsync:是一种快速,多 ...

  5. Java第五次作业--面向对象高级特性(抽象类与接口)

    Java第五次作业--面向对象高级特性(抽象类与接口) (一)学习总结 1.在上周完成的思维导图基础上,补充本周的学习内容,对Java面向对象编程的知识点做一个全面的总结. 2.汽车租赁公司,出租汽车 ...

  6. Maven(一)Maven 的概念和安装

    Maven 的概念和安装 Maven 是什么 首先 Maven 肯定是一个造福人类的好东西,它可以省去我们构建项目中引入 jar 包时的麻烦,还有利于项目的模块化开发等等等好处.在如今项目中大体都是使 ...

  7. 在springboot中使用swagger2

    1.在springboot中使用swagger的话,首先在pom文件中引入依赖 <!-- https://mvnrepository.com/artifact/io.springfox/spri ...

  8. 代码中批量执行Oracle SQL语句

    今天在写一个工具(winform),作用是批量的INSERT OR  UPDATE ORACLE数据库中的一个表. 执行的时候老是报错“[911] ORA-00911: invalid charact ...

  9. Django的性能优化

    Django的性能优化   一,利用标准数据库优化技术 传统数据库优化技术博大精深,不同的数据库有不同的优化技巧,但重心还是有规则的.在这里算是题外话,挑两点通用的说说: 索引,给关键的字段添加索引, ...

  10. idea新建javaweb工程

    最近尝试了idea的使用,将idea建立javaweb工程的步骤记录下来 1.方框里边是重点 2.next后输入工程文件名点击finish 3.如图看到项目文件夹里边没有WEB-INF文件夹及里边的w ...