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

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来查找:
//*[@class='android.widget.Toast']//*[contains(@text,"XXX")] (XXX是tosat信息中的部分内容)测试程序:APIDemos
测试内容:直接进入View下面的Pop menu 界面,然后点击操作按钮产生toast,并进行断言。
步骤:
由于我们使用APIDemos来进行测试,所以可以跳过前面的步骤,直接打开我们要使用的Pop menu 界面去进行操作。但是正常app测试是无法这样操作的。
运行命令:
#iOS和Linu系统
adb shell dumpsys window | grep mCurrent
#Windows系统
adb shell dumpsys window | find "mCurrent"

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"。
<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>
一般一个页面只用一个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
使用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有什么区别?