Poco元素定位和指令碼編寫順序
以下基於
python3.8;airtestIDE1.2.13;airtest1.2.4;pocoui1.0.85
Airtest框架講的差不多了,本期開始講Poco框架,注意:Poco框架和Airtest框架很多API是同名的,但使用方法完全不一樣!!!一定不要搞混了,我初學時也經常搞混,這點一定要注意!
具體Poco框架和Airtest框架是什麼關係,可以看之前文章:Airtest Project——UI自動化利器介紹
今天的主題是Poco框架的元素定位,在講之前我們先普及一個基礎知識,就是Poco框架指令碼內容的編寫順序,新手經常會掉這個坑裡。
Poco指令碼編寫順序
在講之前不熟悉Poco的可以先看下歷史文章:
AirtestIDE實踐二:Poco框架試用
Airtest之使用Poco測試Android原生應用
Airtest之使用Poco測試iOS原生應用
正確的Poco指令碼編寫順序應該是:連線裝置-->開啟應用&等待應用啟動完成-->初始化poco
新手不按這個順序的話,有可能出現各種異常報錯。
純程式碼連線裝置方法可以看之前的Airtest API精講之裝置連線管理API集合
示例:
#-*-encoding=utf8-*-
__author__="測試工程師小站"
fromairtest.core.apiimport*
frompoco.drivers.android.uiautomationimportAndroidUiautomationPoco
#連線裝置、初始化日誌路徑
auto_setup(__file__,logdir=True,devices=["Android:///"])
#啟動計算器
start_app("com.miui.calculator")
sleep(3)
#初始化安卓原生poco
poco=AndroidUiautomationPoco(use_airtest_input=True,screenshot_each_action=False)
#依次點1+1=,這塊程式碼可以使用IDE左下的錄製功能
poco("com.miui.calculator:id/digit_1").click()
poco("com.miui.calculator:id/op_add").click()
poco("com.miui.calculator:id/digit_1").click()
poco("com.miui.calculator:id/btn_equal_s").click()
#獲取結果控制元件的文字並斷言,可以使用IDE左下的鎖定功能,並找到結果控制元件
r=poco("com.miui.calculator:id/result").get_text()
assert_equal("=2",r,"結果=2")
Poco元素定位
Poco元素定位需要用到AirtestIDE中的'Poco輔助窗'功能,之前有介紹AirtestIDE基本功能(一)
AirtestIDE的錄製功能可自動生成元素定位程式碼,但和所有自動化工具的錄製功能一樣,現在的工具還沒有那麼智慧,錄製出的定位程式碼可能無法定位、程式碼太長太冗餘、相容性不好(下個版本UI有一點小改動就導致定位失效)。所以錄製可以輔助,但一定還要熟練掌握定位基礎和技巧。
Poco官方將元素定位分為了:基本選擇器、相對選擇器、空間選擇器,以及通過正則表示式匹配。熟悉Selenium或Appium的朋友可以無縫上手。
基本選擇器
我們對元素定位的目標就是唯一,即使下個版本有一些UI改動,也能儘量不影響之前的定位程式碼。像Selenium、Appium,如果開發配合,應該給所有元素一個唯一的id值,我們通過id即可唯一定位一個元素。在Poco中,'name'屬性就是類似於Selenium的'id'屬性的存在。
我們以安卓設定為例
一個經典的定位:
poco(name="android:id/title",text="語言與輸入法")
#在poco中,如果不寫屬性名,則預設該屬性為name,所以也可以寫成
poco("android:id/title",text="語言與輸入法")
#在這個例子中,設定中的所有文字選項的name都是"android:id/title"
#但"text"屬性是唯一的,所以可以寫成更簡單的
poco(text="語言與輸入法")
上面就是一個簡單的定位的例子,一般情況下,如果開發配合,給"name"屬性都設為全域性唯一名稱,那我們的定位工作將會非常簡單。如果受公司所限開發無法配合,一般"text"屬性也是唯一的。
我們定位的原則就是用最少的屬性全域性唯一定位一個元素,優先用"name"、"text"單屬性定位,如果單屬性定位不唯一,就組合起來使用,仍不唯一時,可以繼續加入其他屬性,如"type"、"touchable"、"clickable"、"visible"等。
空間選擇器
空間選擇器就是有一組元素時,利用索引下標來確定唯一元素,下標是從0開始。
下來我們以Airtest官網提供的Unity的App為例
#我們的目標是點選鯊魚圖片元素
#鯊魚是第1個'Image',即下標0
poco("Image")[0].click()
#也可以和相對選擇器組合使用
node=poco("fish")[0]#先定位到鯊魚的整個節點
#上面那行也可以拆分寫成2行
#node_list=poco("fish")
#node=node_list[0]
shark=node.child("Image")#再定位到其下的"Image"元素
shark.click()
但使用空間選擇器需要注意,有時我們App內的元素索引是會變的,比如上面例子中第1個(索引0)是鯊魚,假如我們點選後,又多出來一個鯉魚,並且排在第1位,這時候鯊魚就變第2個了,所以還想再次點選鯊魚的話,需要重新定位一次
poco("Image")[1].click()
相對選擇器
有時候,通過基本選擇器、空間選擇器無法定位到元素時,可以使用相對選擇器來定位。
上面我們已經例舉了一個相對選擇器的例子,即先定位到鯊魚的整個節點元素'fish',再定位他的子元素'Image'
Poco有如下相對選擇器:
-
child(name=None, **attrs)
返回第1個符合條件的子元素 -
children()
返回所有子元素 -
offspring(name=None, **attrs)
返回符合條件的子孫元素 -
parent()
返回父元素 -
sibling(name=None, **attrs)
返回符合條件的兄弟元素
還是以此圖為例:
#返回playLocalPositioning的第1個子元素,即鯊魚的node元素'fish'
shark_node=poco("playLocalPositioning").child()
#返回鯊魚的子元素name
shark_name=shark_node.child("name")
print(shark_name.get_text())
#返回playLocalPositioning的所有子元素
fish_list=poco("playLocalPositioning").children()
shark_node=fish_list[0]
#返回playLocalPositioning的所有符合條件的子孫元素(下一層)
fish_list=poco("playLocalPositioning").offspring("fish")
shark_node=fish_list[0]
#返回playLocalPositioning的所有符合條件的子孫元素(下下一層)
fish_list=poco("playLocalPositioning").offspring("name")
shark_name=fish_list[0]
print(shark_name.get_text())
#返回Canvas的所有符合條件的子孫元素(下下下下一層)
shark_name=poco("Canvas").offspring("name")
#返回鯊魚文字的父節點
shark_node=poco(text="shark").parent()
#返回鯊魚文字的兄弟節點圖片
shark_img=poco(text="shark").sibling("Image")
#返回鯊魚node節點的兄弟節點
#按理說應該是3個fish節點,但poco會加上其父節點playLocalPositioning,不知道是不是bug
fish_list=poco(text="shark").parent().sibling()
#所以我們限定一下只要3個fish節點
fish_list=poco(text="shark").parent().sibling("fish")
#通過鯊魚文字元素定位珍珠文字元素
pearl_node=poco(text="shark").parent().sibling("fish")[2]
pearl_name=pearl_node.child("name")
print(pearl_name.get_text())
#列印所有圖片的名字文字
fish_list=poco("fish")
forfishinfish_list:
print(fish.child("name").get_text())
通過正則表示式定位元素
Poco元素的各個屬性,都是字串,所以正則定位元素和Python中的字串正則匹配是一樣的。不會正則的可以先去學Python正則。
我們以第1個例子安卓配置為例,我們要定位"語言與輸入法",但是不同的MIUI版本或是三星、華為手機該項名稱可能是不一樣的,比如:
MIUI10該元素的text="語言與輸入法"
MIUI11該元素的text="語言和輸入法"
三星該元素的text="輸入法"
華為該元素的text="輸入法設定"
為了同時相容4臺手機,我們可以通過if來判斷手機型號然後定位元素,很複雜而且要寫很多程式碼,這時就可以使用正則定位元素
#一行程式碼同時相容4臺手機
poco(textMatches=".*輸入法.*")
或者有時name屬性是類似的,我們想定位所有類似元素。如有3個元素name分別是"color_red"、"color_green"、"color_yellow"、
#返回3個顏色元素的一個list
color_list=poco(nameMatches="color_.*")
除了最常見的textMatches、nameMatches和typeMatches,其實大部分的屬性都可以用這種方式來傳遞正則表示式,只要能夠用 poco(xx=預期屬性值) 來選擇的控制元件,就可以用 poco(xxMatches=預期屬性值的正則表示式) 來進行匹配定位。
---------------------------------------------------------------------------------
關注微信公眾號即可在手機上查閱,並可接收更多測試分享~