1. 程式人生 > 其它 >Poco元素定位和指令碼編寫順序

Poco元素定位和指令碼編寫順序

上期回顧:Airtest區域性截圖+找圖、截圖另存為


以下基於
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=預期屬性值的正則表示式) 來進行匹配定位。

---------------------------------------------------------------------------------

關注微信公眾號即可在手機上查閱,並可接收更多測試分享~