前言
Poco 是一款基於UI控件識別的自動化測試框架,目前支持Unity3D/cocos2dx-*/Android原生app/iOS原生app/微信小程序,也可以在其他引擎中自行接入poco-sdk來使用,原理:類似appium,基於UI控件搜索的自動化測試框架,定位目標控件,然后調用函數方法對目標控件進行操作。
使用Poco選擇UI對象
基本選擇器(Basic Selector)
在poco實例后加一對括號就可以進行UI選擇了。選擇器會遍歷所有UI,將滿足給定條件的UI都選出來並返回。
括號里的參數就是所給定的條件,用屬性名值對表示,其中第一個參數固定表示 節點名 其余可選參數均表示節點的屬性及預期的屬性值。
# select by node name
poco('bg_mission')
# select by name and other properties
poco('bg_mission', type='Button')
poco(textMatches='^據點.*$', type='Button', enable=True)
相對選擇器(Relative Selector)
直接用節點屬性沒法選出你所想要的UI時,還可以通過UI之間的渲染層級關系進行選擇,例如父子關系、兄弟關系、祖先后代關系。
# select by direct child/offspring
poco('main_node').child('list_item').offspring('item')
空間順序選擇器(Sequence Selector)
按照序號(順序)進行選擇總是按照空間排布順序,先從左往右,再像之前那樣一行一行從上到下,如下圖中的數字標號,就是索引選擇的序號。索引選擇有個特例,一旦進行選擇后,如果UI的位置發生了變化,那么下標序號仍然是按照選擇的那一瞬間所確定的值。即,如果選擇時1號UI現在去到了6號的位置,那么還是要用poco(...)[1] 來訪問,而不是6.如果選擇了之后,某個UI消失了(從界面中移除或者隱藏了),那么如果再訪問那個UI則可能會發生異常,其余的UI仍可繼續訪問。
items = poco('main_node').child('list_item').offspring('item')
print(items[0].child('material_name').get_text())
print(items[1].child('material_name').get_text())
迭代一組對象(Iterate over a collection of objects)
下面代碼片段展示如何迭代遍歷一組UI
# traverse through every item
items = poco('main_node').child('list_item').offspring('item')
for item in items:
item.child('icn_item')
讀取屬性(Get object properties)
mission_btn = poco('bg_mission')
print(mission_btn.attr('type')) # 'Button'
print(mission_btn.get_text()) # '據點支援'
print(mission_btn.attr('text')) # '據點支援' equivalent to .get_text()
print(mission_btn.exists()) # True/False, exists in the screen or not
操作UI對象(Object Proxy Related Operation)
點擊(click)
點擊默認點在 anchorPoint 上,每個UI都會有一個 anchorPoint ,也就是檢視器(Inspector)中UI包圍盒的那個紅點,大部分情況下 anchorPoint 都在UI包圍盒的正中央。如果想指定其他的點擊位置,可以傳一個參數到 click 方法中,這個參數是一個用list或tuple表示的2維向量,其 [x, y] 值分別表示相對於包圍盒左上角的偏移量,左上角為 [0, 0] ,右下角為 [1, 1] ,具體用法請見 局部坐標系 。
下面的例子展示 click 的幾種用法
poco('bg_mission').click()
poco('bg_mission').click('center')
poco('bg_mission').click([0.5, 0.5]) # equivalent to center
poco('bg_mission').focus([0.5, 0.5]).click() # equivalent to above expression
滑動(swipe)
swipe操作同樣是以 anchorPoint 為起點,如果你想改變起點請使用下面的 focus 方法,然后朝給定向量所代表的方向滑動,距離也就是向量的長度。關於向量的坐標如何表示可以參考 歸一化坐標系 。
joystick = poco('movetouch_panel').child('point_img')
joystick.swipe('up')
joystick.swipe([0.2, -0.2]) # swipe sqrt(0.08) unit distance at 45 degree angle up-and-right
joystick.swipe([0.2, -0.2], duration=0.5)
拖拽(drag)
與 swipe 不同的是, darg 是從一個UI拖到另一個UI,而 swipe 是將一個UI朝某個方向拖動。
下面例子展示如何使用 drag_to 方法
poco(text='突破芯片').drag_to(poco(text='岩石司康餅'))
局部定位(focus (local positioning))
所有UI相關的操作都默認以UI的 anchorPoint 為操作點,如果想自定義一個點那么可以使用 focus 方法。調用此方法將返回 新的 設置了默認 焦點 的UI,重復調用則以最后一次所調用的為准。focus 所使用的是局部坐標系,因此同樣是UI包圍盒的左上角為原點,x軸向右,y軸向下,並且包圍盒長寬均為單位1。很顯然中心點就是 [0.5, 0.5] 。下面的例子會展示一些常用的用法。
poco('bg_mission').focus('center').click() # click the center
將 focus 和 drag_to 結合使用還能產生卷動(scroll)的效果,下面例子展示了如何將一個列表向上卷動半頁。
scrollView = poco(type='ScollView')
scrollView.focus([0.5, 0.8]).drag_to(scrollView.focus([0.5, 0.2]))
等待出現(wait)
在給定時間內等待一個UI出現並返回這個UI,如果已經存在畫面中了那就直接返回這個UI。 如果超時了還沒有出現,同樣也會返回,但是調用這個UI的操作時會報錯。類似的操作還有,見 wait_for_appearance
poco('bg_mission').wait(5).click() # wait 5 seconds at most,click once the object appears
poco('bg_mission').wait(5).exists() # wait 5 seconds at most,return Exists or Not Exists
全局操作(Global Operation)
在沒有選定或指定UI的情況下也可以進行操作(模擬輸入),也叫全局操作。
點擊(click)
poco.click([0.5, 0.5]) # click the center of screen
poco.long_click([0.5, 0.5], duration=3)
滑動(swipe)
# swipe from A to B
point_a = [0.1, 0.1]
center = [0.5, 0.5]
poco.swipe(point_a, center)
# swipe from A by given direction
direction = [0.1, 0]
poco.swipe(point_a, direction=direction)
截屏(snapshot)
截屏幕並以base64編碼返回。截圖的格式(png, jpg, …)由對應的sdk實現決定,大多數情況下是png。詳見 ScreenInterface.getScreen
from base64 import b64decode
b64img, fmt = poco.snapshot(width=720)
open('screen.{}'.format(fmt), 'wb').write(b64decode(b64img))
異常處理(Exceptions)
PocoTargetTimeout
from poco.exceptions import PocoTargetTimeout
try:
poco('guide_panel', type='ImageView').wait_for_appearance()
except PocoTargetTimeout:
# bugs here as the panel not shown
raise
PocoNoSuchNodeException
from poco.exceptions import PocoNoSuchNodeException
img = poco('guide_panel', type='ImageView')
try:
if not img.exists():
img.click()
except PocoNoSuchNodeException:
# If attempt to operate inexistent nodes, an exception will be thrown
pass