Toast
含义
- 为了给当前视图显示一个浮动的显示块,与dialog不同它永远不会获得焦点
- 显示时间有限,根据用户设置的显示时间后自动消失
- 本身是个系统级别的控件,它归属系统settings,当一个app发送消息的时候,不是自己造出来的这个弹框,它是发给系统,由系统统一进行弹框,这类的控件不在app内、需要特殊的控件识别方法
toast定位
- appium使用uiautomator底层的机制来分析抓取toast,并且把toast放到控件树里面,但本身并不属于控件
- automationName:uiautomator2 这个是appium本身的设置就自带的,不需要额外添加,默认就是uiautomator2
- getPageSource是无法找到toast的
- 必须使用xpath去查找
- //*[@class=“android.widget.Toast”]
- //*[contains(@text,“xxxxx”)]
实例:appium自带的app测试toast
- adb shell dumpsys window | findstr mCurrent 这个命令可以找到当前的activity,不知道Android高版本是不是还ok,由于api demo权限高,可直接跳到这个activity运行,其他app就不ok了
- driver.page_source可以打印当前的页面,可以找到toast的伪控件
- 打印toast的text出来
driver.page_source打印出来的东西,包含toast
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?> <hierarchy index="0" class="hierarchy" rotation="3" width="810" height="1440"> <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][810,1440]" 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][810,1440]" 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,41][810,136]" 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,41][810,136]" 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="[27,65][324,111]" 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,136][810,1440]" 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,136][810,1440]" 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="[297,136][513,217]" displayed="true" /> </android.widget.LinearLayout> </android.widget.FrameLayout> </android.view.ViewGroup> </android.widget.FrameLayout> #这里就找到了Tast的控件了 <android.widget.Toast index="1" package="com.android.settings" class="android.widget.Toast" text="Clicked popup menu item Search" checkable="false" checked="false" clickable="false" enabled="false" focusable="false" focused="false" long-clickable="false" password="false" scrollable="false" selected="false" bounds="[0,0][0,0]" displayed="false" /> </hierarchy>View Code
from appium import webdriver from selenium.webdriver.support import expected_conditions from selenium.webdriver.support.wait import WebDriverWait from appium.webdriver.common.mobileby import MobileBy as By class TestFind(): def setup(self): self.desire_cap= { "platformName":"android", "deviceName":"127.0.0.1:7555", "appPackage":"io.appium.android.apis", "appActivity":"io.appium.android.apis.view.PopupMenu1", "noReset":"true", "unicodeKeyboard":True } self.driver=webdriver.Remote("http://127.0.0.1:4723/wd/hub",self.desire_cap) self.driver.implicitly_wait(5) def test_search(self): """ 1.打开appium的演示app 2.直接进入到测试toast的界面 3.点击显示toast的按钮,然后通过driver.page_source获取页面 4.找到toast的伪控件 5.打印出toast的值出来 :return: """ #点击Make a Popup的控件 self.driver.find_element(By.XPATH,'//*[@text="Make a Popup!"]').click() #点击search的控件 self.driver.find_element(By.XPATH, '//*[@text="Search"]').click() #打印整个布局页面的xml出来 print(self.driver.page_source) #打印出toast的值 print(self.driver.find_element(By.XPATH, '//*[contains(@text,"popup menu")]').text)对应的python脚本代码
参数化
一些小细节
- 参数化要解决的是一个用例可以复用的问题,比如一个用例重复使用不同的数据,就可以使用参数化,比如同一个用例,有搜索股价,比较股价,都是同一个方法,只是数据不太一样
- @pytest.mark.parametrize(‘searchkey,type,price’,[
(‘alibaba’,‘BABA’,180),
(‘xiaomi’,‘01810’,10) - 用上面的方法去使用参数化
- def test_search(self,searchkey,type,price) 函数的参数要和参数化的参数的数量一样,字符串也要一样
- 一个用例,有2组参数化,就会运行两次setup和teardown的方法
- 使用self.driver.find_element(By.ID,“com.xueqiu.android:id/search_input_text”).send_keys(f"{searchkey}"),使用f"{searchkey}"是一个好东西,可以搭配参数化使用
from appium import webdriver from appium.webdriver.common.mobileby import MobileBy as By from selenium.webdriver.support import expected_conditions from selenium.webdriver.support.wait import WebDriverWait import pytest class TestFind(): #设置caps的值 def setup(self): self.desire_cap= { #默认是Android "platformName":"android", #adb devices的sn名称 "deviceName":"127.0.0.1:7555", #包名 "appPackage":"com.xueqiu.android", #activity名字 "appActivity":".view.WelcomeActivityAlias", "noReset":"true", "unicodeKeyboard":True } #运行appium,前提是要打开appium server self.driver=webdriver.Remote("http://127.0.0.1:4723/wd/hub",self.desire_cap) self.driver.implicitly_wait(5) #这个加不加都行,因为参数化运行都会有setup的,setup就是启动app的过程了,这个就显得有点多余了 #但好像setup并不会初始化整个app,还会停留在前一个页面上,所以还是加上比较好 def teardown(self): self.driver.find_element(By.XPATH,'//*[@text="取消"]').click() #这是参数化的函数,第一部分是参数化的名字,得和下面的函数参数一模一样,用字符串包含进去 #列表里面的元祖接受具体的参数化的数据,用逗号隔开,和list一样 @pytest.mark.parametrize('searchkey,type,price',[ ('alibaba','BABA',180), ('xiaomi','01810',10) ]) #参数哈的函数的参数要和上面的参数名字保持一致 def test_search(self,searchkey,type,price): """ 1.打开雪球app 2.点击搜索输入框 3.向搜索输入框输入“阿里巴巴” 4.在搜索的结果里选择阿里巴巴,然后点击 5.获取这只上香港 阿里巴巴的股价,并判断这只股价的价格>200 6.通过参数化的方法,用一个用例判断阿里巴巴和小米的股价 :return: """ #显示等待进入主页,等主页的元素都加载好了 WebDriverWait(self.driver, 15).until(expected_conditions.element_to_be_clickable((By.XPATH,'//*[@text="我的"]'))) #点击搜索框 self.driver.find_element(By.ID,"com.xueqiu.android:id/tv_search").click() #向搜索框输入阿里巴巴,小米等参数化的东西f"{searchkey}"是一个好用的东西 self.driver.find_element(By.ID,"com.xueqiu.android:id/search_input_text").send_keys(f"{searchkey}") #找到搜索框预览结果的阿里巴巴,并点击 self.driver.find_element(By.XPATH,f"//*[@text='{type}']").click() #选择HK股价的元素,这里是通过父类的方法去定位的 current_price=self.driver.find_element(By.XPATH,f"//*[@text='{type}']/../../..//*[@resource-id='com.xueqiu.android:id/current_price']") #提取股价的text属性 current_price=float(current_price.text) #判断股价是否大于200 assert current_price > price对应代码
标签:toast,控件,appium,text,self,driver,获取 From: https://www.cnblogs.com/margret/p/16339156.html