上期回顧:Poco API精講之點擊click()、long_click()、double_click()
以下基於
python3.8;airtestIDE1.2.13;airtest1.2.4;pocoui1.0.85
注意:Poco框架和Airtest框架很多API是同名的,但使用方法完全不一樣!!!一定不要搞混了,我初學時也經常搞混,這點一定要注意!
具體Poco框架和Airtest框架是什麼關係,可以看之前文章:Airtest Project——UI自動化利器介紹
今天來講Poco的滑動swipe(),大家不要和Airtest框架的swipe()弄混了。
Airtest框架的swipe()是基於絕對座標或圖片的;Poco的swipe()是基於屏幕相對座標或元素的。
Airtest的swipe()詳情可以看之前的文章:Airtest API精講之swipe()
對座標不熟的可以看之前的文章:Airtest和Poco座標詳解
Poco的swipe分兩種,一種是基於全局操作的swipe、一種是基於UI對象的swipe,兩種API彙總可以看之前的文章
Poco實例(全局操作) API彙總
Poco UI對象 API彙總
Poco基於全局操作的swipe
swipe(p1, p2=None, direction=None, duration=2.0)
滑動
參數:
p1 - 起點,屏幕相對座標,如[0.5,0.5]
p2 - 終點,屏幕相對座標,如[0.6,0.6]
direction - 滑動向量,如[0.1,0.1],從起始點向右10%向下10%滑動。如屏幕爲100*100,起始點爲[0.5,0.5],則是從絕對座標(50,50)滑到(60,60)
duration - 滑動時長,默認2秒
異常:
InvalidOperationException: 座標在屏幕以外時報錯
源碼解析:
# 源碼位置:your_python_path\site-packages\poco\pocofw.py
def swipe(self, p1, p2=None, direction=None, duration=2.0):
try:
duration = float(duration)
except ValueError:
raise ValueError('Argument `duration` should be <float>. Got {}'.format(repr(duration)))
if not (0 <= p1[0] <= 1) or not (0 <= p1[1] <= 1):
raise InvalidOperationException('Swipe origin out of screen. {}'.format(repr(p1)))
if direction is not None:
p2 = [p1[0] + direction[0], p1[1] + direction[1]]
elif p2 is not None:
p2 = p2
else:
raise TypeError('Swipe end not set.')
return self.agent.input.swipe(p1[0], p1[1], p2[0], p2[1], duration)
首先請記住,起/終點或滑動向量,都是屏幕相對座標。
第1個try,用來確定滑動時長變量。
第1個if,判斷起始座標是否超出屏幕範圍。
第2個if-else,如果指定了滑動向量,則通過滑動向量計算出終點座標;如果給了終點座標,則直接使用
最後return,直接調用代理的滑動,並且把計算好的起/終點座標傳進去。
示例:
from airtest.core.api import *
from poco.drivers.unity3d import UnityPoco
auto_setup(__file__)
poco = UnityPoco()
# 從中心向右滑,滑動時長2秒
poco.swipe([0.5,0.5], [0.9,0.5])
# 從中心向左上滑動(左上屏幕寬的10%長的10%的那個點),滑動過程持續3秒
poco.swipe([0.5,0.5], direction=[-0.1,-0.1], duration=3)
Poco基於UI對象的swipe
swipe(direction, focus=None, duration=0.5)
滑動
參數:
direction - 滑動方向,可以是屏幕相對座標或是指定方向'up', 'down', 'left', 'right'。'up'=[0, -0.1], 'down'=[0, 0.1], 'left'=[-0.1, 0], 'right'=[0.1, 0]。如[0, -0.1],指元素長的方向不動,整個屏幕寬-10%的位置,即基於元素中心點垂直向上。
focus - 元素相對座標,如[0.1,0.1],指元素長、寬各10%的位置,即左上角,取值範圍0~1
duration - 滑動時長,默認0.5秒
異常:
PocoNoSuchNodeException:元素不存在
源碼解析:
# 源碼位置:your_python_path\site-packages\poco\proxy.py
@wait
def swipe(self, direction, focus=None, duration=0.5):
try:
duration = float(duration)
except ValueError:
raise ValueError('Argument `duration` should be <float>. Got {}'.format(repr(duration)))
focus = focus or self._focus or 'anchor'
dir_vec = self._direction_vector_of(direction)
origin = self.get_position(focus)
self.poco.pre_action('swipe', self, (origin, dir_vec))
ret = self.poco.swipe(origin, direction=dir_vec, duration=duration)
self.poco.post_action('swipe', self, (origin, dir_vec))
return ret
第1個try,用來確定滑動時長變量。
focus = focus or self._focus or 'anchor'
origin = self.get_position(focus)
獲取指定的錨點,默認是中心點。
並通過get_position()
帶入錨點,計算出起始座標(屏幕相對座標)
dir_vec = self._direction_vector_of(direction)
通過self._direction_vector_of()
計算出終點座標(屏幕相對座標)
ret = self.poco.swipe(origin, direction=dir_vec, duration=duration)
可以看到,基於UI對象的swipe最終還是通過上面剛剛講過的 Poco基於全局操作的swipe來執行。
接下來我們看看上面計算終點座標的self._direction_vector_of()
源碼:
# 源碼位置:your_python_path\site-packages\poco\proxy.py
def _direction_vector_of(self, dir_):
if dir_ == 'up':
dir_vec = [0, -0.1]
elif dir_ == 'down':
dir_vec = [0, 0.1]
elif dir_ == 'left':
dir_vec = [-0.1, 0]
elif dir_ == 'right':
dir_vec = [0.1, 0]
elif type(dir_) in (list, tuple):
dir_vec = dir_
else:
raise TypeError('Unsupported direction type {}. '
'Only "up/down/left/right" or 2-list/2-tuple available.'.format(type(dir_)))
return dir_vec
代碼很簡單,如果你指定了上/下/左/右關鍵字,則替換爲指定的屏幕相對座標(向指定方向滑動屏幕長或寬的10%距離);如果你直接給的就是座標,則直接使用。
另外說下此處頭上的@wait裝飾器,就是加了一個wait_for_appearance()的等待:
# 源碼位置:your_python_path\site-packages\poco\proxy.py
def wait(func):
@wraps(func)
def wrapped(proxy, *args, **kwargs):
try:
return func(proxy, *args, **kwargs)
except PocoNoSuchNodeException as e:
try:
proxy.wait_for_appearance(timeout=proxy.poco._pre_action_wait_for_appearance)
return func(proxy, *args, **kwargs)
except PocoTargetTimeout:
raise e
return wrapped
wait裝飾器邏輯:首先嚐試直接執行原方法,如果報PocoNoSuchNodeException的錯,則通過wait_for_appearance()等待
對裝飾器不熟的可以看:Python三大器之裝飾器
示例:
qasite = poco('測試工程師小站')
# 從元素中心向上滑動屏幕寬10%(即1000*0.1)的距離
qasite.swipe([0, -0.1])
# 從元素中心向上滑動屏幕寬10%的距離,參數使用關鍵字
qasite.swipe('up')
# 從元素左上角向上滑動屏幕寬10%的距離,滑動過程持續3秒
qasite.swipe(direction='up', focus=[0.1,0.1], duration=3)
示例中第3個,假設屏幕是1000*1000,元素絕對長寬爲400*400,元素位於屏幕中心即[500,500]
那麼可以算出元素左上角座標是[300,300]
focus=[0.1,0.1]
表示是在元素長寬各10%的那個點,可以算出該點屏幕絕對座標爲[300+400*0.1,300+400*0.1]=[340,340]
向上滑屏幕寬10%(1000*0.1)的距離,所以可以算出終點屏幕絕對座標爲[340,240]
所以最終就是從[340,340]滑到了[340,240],所以如果用Airtest框架的swipe,就是swipe([340,340],[340,240])
圖片手工繪製,不夠精準,湊合着看
這裏給大家算出屏幕絕對座標是爲了方便大家理解原理,實際使用的時候,你不用換算成屏幕絕對座標,你就直接代入相對座標用就可以。如果你算不準相對座標,可以在AirtestIDE上開啓顯示相對座標,這樣來獲取,或者調試幾次也能找到你要的位置了。
需要注意的是,ios的duration是按下的時間,而不是滑動的時間,也許wda就是這樣設計的吧,或者是bug。
from airtest.core.api import *
from poco.drivers.ios import iosPoco
auto_setup(__file__)
poco = iosPoco()
# 按下3秒,再從中心向右滑
poco.swipe([0.5,0.5], [0.9,0.5], duration=3)
# 按下3秒,再將元素向下滑
poco("測試工程師小站").swipe(direction='down', duration=3)
---------------------------------------------------------------------------------
關注微信公衆號即可在手機上查閱,並可接收更多測試分享~