异常处理

在写测试用例时,以下4种异常是需要处理的,其他的异常多数是脚本的bug,如果你觉得是poco的问题,不要犹豫,随时给我们提issue。

InvalidOperationException

这个异常特指无效的操作,或者说不起作用的操作,例如点击到了屏幕外面,或者对一个图片设置text属性(输入框才能设置text属性)。虽然这个异常并不会对应用造成什么实质性影响,但是还是要尽可能避免,以免测试脚本里逻辑混乱或测试结果不稳定。

# coding=utf-8

from poco.drivers.unity3d import UnityPoco
from poco.exceptions import InvalidOperationException

poco = UnityPoco()

try:
    poco.click([1.1, 1.1])  # click outside screen
except InvalidOperationException:
    print('oops')

PocoNoSuchNodeException

如果从一个不存在的UI控件读取属性或控制它,那就会出现这个异常。测试一个UI控件是否存在可以调用UI代理的 .exists() 方法。

注解

  • 如果只是选择了一个UI但是不去操作或者读取属性是不会产生异常的,因为选择UI只是将选择的条件存储下来,等到执行具体的操作时才会去game/app中查找和选择。
  • 如果有个透明的UI或者你看不见(在屏幕外面或者尺寸为0),他同样也是存在的,同样也可以对他进行操作或者读取属性。只有不在hierarchy树中的才是不存在的。
../../../_images/exception2.gif
# coding=utf-8

from poco.drivers.unity3d import UnityPoco
from poco.exceptions import PocoNoSuchNodeException

poco = UnityPoco()

node = poco('not existed node')  # select will never raise any exceptions
try:
    node.click()
except PocoNoSuchNodeException:
    print('oops!')

try:
    node.attr('text')
except PocoNoSuchNodeException:
    print('oops!')

print(node.exists())  # => False. this method will not raise

PocoTargetTimeout

这个异常只会在你主动等待UI出现或消失时抛出,和 PocoNoSuchNodeException 不一样,当你的操作速度太快,界面来不及跟着变化的话,你只会遇到 PocoNoSuchNodeException 而不是 PocoTargetTimeout ,其实就是在那个UI还没有出现的时候就想要进行操作。

下面的例子展示测试脚本如何与UI保持同步,并处理 PocoTargetTimeout 异常

../../../_images/exception3.gif
# coding=utf-8

from poco.drivers.unity3d import UnityPoco
from airtest.core.api import connect_device
from poco.exceptions import PocoTargetTimeout


poco = UnityPoco()

# UI is very slow
poco('btn_start').click()
star = poco('star')
try:
    star.wait_for_appearance(timeout=3)  # wait until appearance within 3s
except PocoTargetTimeout:
    print('oops!')
    time.sleep(1)

PocoTargetRemovedException

与上面 PocoTargetTimeout 不同,如果操作速度远远慢于UI变化的速度,那*很可能*会出现这个异常。这个异常仅当去访问或操作一个刚才还在但现在不在的UI控件才会出现,并且一般情况下基本不会出现。

下面例子展示点击一个已经不存在的UI控件的效果

# coding=utf-8

from poco.exceptions import PocoTargetRemovedException, PocoNoSuchNodeException


poco = Poco(...)

start = poco('start')
print(start.exists())  # => True.
start.click()
print(start.exists())  # => False
try:
    start.click()
except PocoTargetRemovedException:
    print('oops!')

# IMPORTANT NOTE:
# `start2` is different from `start` !
# `start` is tracking the UI at initial and it knows itself was removed but `start2`
# does not know anything before.
start2 = poco('start')
try:
    start2.click()
except PocoNoSuchNodeException:
    print('oops!')

注解

这个异常仅会在一些poco-sdk实现中,所以更可靠的做法是必要的情况下显示地去调用 .exists() 去判断UI是否存在。

注解

In poco.drivers.std.StdPoco, this exceptions is never raised!

# coding=utf-8

from poco.drivers.unity3d import UnityPoco
from airtest.core.api import connect_device


poco = UnityPoco()

# no PocoTargetRemovedException case
start = poco('start')
print(start.exists())  # => True.
start.click()
print(start.exists())  # => False

# IMPORTANT: In Unity3d, this operation will click the same coordinate as previous
# and no matter what actually happens
start.click()

更多示例: