上期回顾:Airtest自动化多设备测试框架DreamMultiDevices
以下基于
python3.8;airtestIDE1.2.14;airtest1.2.6;pocoui1.0.87
运行Poco脚本的时候,有没有遇到过RpcTimeout的报错,形如:
File "poco\proxy.py", line 23, in wrapped
File "poco\proxy.py", line 283, in click
File "poco\proxy.py", line 563, in get_position
File "poco\proxy.py", line 39, in wrapped
File "poco\proxy.py", line 684, in attr
File "poco\proxy.py", line 819, in _do_query
File "poco\freezeui\hierarchy.py", line 89, in select
File "poco\sdk\Selector.py", line 77, in select
File "poco\sdk\Selector.py", line 70, in getRoot
File "poco\freezeui\hierarchy.py", line 35, in getRoot
File "poco\utils\simplerpc\utils.py", line 13, in new_func
File "poco\utils\simplerpc\simplerpc.py", line 78, in wait
poco.utils.simplerpc.simplerpc.RpcTimeoutError: <poco.utils.simplerpc.simplerpc.Callback object at 0x000001D120A1E8D0>(rid=41e44621-1ba7-423d-a6b2-e46ba46f0f79)
Python Poco库是通过RPC与接了Poco SDK的游戏进行通信,我们做任何操作的时候,都会先从游戏中拉取整个Hierarchy(UI树)的信息到PC上,然后Python Poco库再去匹配到需要的信息。所以在这个链条上,任何一个节点出错,都可能导致RpcTimeoutError,比如USB供电不稳定、USB线有问题、ADB有问题、各种环境版本问题、游戏内SDK传输有问题等等。但最有可能的还是场景Hierarchy(UI树)中的GameObject(元素)数量过大,导致传输UI信息的时候,adb无法及时做转发,信息丢失,进而出现了超时。游戏界面越复杂、元素越多,越容易出现这个问题。
什么意思呢,比如你的Hierarchy信息一共有几MB,你频繁的wait或click等操作,在Poco底层都会造成一次或多次的DUMP,从而频繁去拉取Hierarchy,造成RpcTimeoutError,严重的话可能还会卡死游戏内的Poco Server。类似于测试的压力测试,当压力小时,一切正常,当压力到达顶端时,各种性能指标都会下降,有些请求可能会失败,但整体还能工作。当压力超出顶点,导致链条上某个节点卡死或崩溃,整个系统就都不能工作了。
网上有人通过添加RPC的方法解决这个问题,我们看下他遇到的问题和解决方案:
https://answer.uwa4d.com/question/5dabdb05efeb9d3d55d15ab0
问题
airtest在战场中的卡顿问题
测试设备是华为荣耀10
在测试中需要等待战斗结束,代码中是用poco(‘UIRoot’).child(‘BattleEnd’).wait_for_appearance(100000)实现的,但是我发现执行到这段代码开始,每隔一两秒画面就会卡顿一次,然后我把"Poco辅助窗"改成"Stop",把Device窗口也关掉,卡顿依然存在,这个卡顿是怎么造成的,有什么方法可以解决么?
解决方案
自问自答一下,项目有管理ui的管理器,所以在PocoManager添加了rpc方法
[RPC]
private object IsModuleVisible(List<object> param)
然后air代码里添加
from poco.utils.simplerpc.utils import sync_wrapper
from poco.drivers.unity3d import UnityPoco
import time;
from poco.exceptions import PocoTargetTimeout
auto_setup(__file__)
poco = UnityPoco()
@sync_wrapper
def IsModuleVisible(module):
return poco.agent.c.call("IsModuleVisible", module)
def WaitForAppearance(module, timeout = 120):
start = time.time()
while not IsModuleVisible(module):
poco.sleep_for_polling_interval();
if time.time() - start > timeout:
raise PocoTargetTimeout('Appearance', module)
然后调用这个自定义的WaitForAppearance就没有卡顿了,不知道还有什么更简单的解决方法?
他在Poco SDK端添加了一个新的RPC接口IsModuleVisible,这样等待元素的时候,通过调用这个接口,返回True或False,来判断元素是否出现。因为只返回一个布尔值,所以很快。当元素出现的时候,再去调用如click()方法,此时会用Poco原有的拉取整个Hierarchy的逻辑。这样一来,整个过程只拉取了一次全量Hierarchy。需要同时修改Python Poco源码和Poco SDK源码,如果能力有限,可以请开发帮忙修改。
但是,如果你游戏的Hierarchy真的超大,还是会出现问题。所以更彻底的优化方案是,Python Poco库发送拉取请求,游戏Poco服务做处理只返回相关的元素信息,而不是整个Hierarchy,这将是一袋大米和一粒大米的区别。当然,将比上面的修改更复杂,可能需要开发1-2周的工作量来熟悉/开发/调试。
好了,如果开发不帮忙修改,那只能自救了,虽然不治本但治标啊。Airtest图片查找是自带重试的,那Poco我们能不能也加个重试呢?
在不修改Poco源码的情况下,我们可以通过装饰器来解决。
不熟悉装饰器的可以先学习一下:python装饰器这一篇就够了、python装饰器实现自动化失败后重试;进阶:Python三大器之装饰器
直接上代码:
# qasite_lib.py
from functools import wraps
from poco.utils.simplerpc.simplerpc import RpcTimeoutError
def qasite_retry(func):
@wraps(func)
def wrapper(*args, **kwargs):
for i in range(2):
try:
return func(*args, **kwargs)
except RpcTimeoutError:
print(f'{func.__name__} 连接超时,重试一次')
return func(*args, **kwargs)
return wrapper
很简单,就是通过try发现RpcTimeoutError时,则忽略,重试一次。重试次数大家可以调整。
接着去二次封装各种操作,以上面网友遇到的wait_for_appearance为例
# qasite_lib.py
@rpctimeout_retry
def qasite_wait_appearance(element, timeout: int = 120) -> bool:
element.wait_for_appearance(timeout)
print(f"{element}出现了")
return True
用例中应用:
from airtest.core.api import *
from poco.drivers.unity3d import UnityPoco
from qasite_lib import *
auto_setup(__file__)
poco = UnityPoco()
button = poco("button")
qasite_wait_appearance(button)
qasite_click(button) # 这个请参照qasite_wait_appearance自行实现
我们上面说了,如果只是超时,这种方法可以解决。如果是游戏内Poco服务卡死了,重试多少次也没用了。
---------------------------------------------------------------------------------
关注微信公众号即可在手机上查阅,并可接收更多测试分享~
标签:qasite,Poco,Hierarchy,py,poco,RpcTimeoutError,Airtest,line From: https://www.cnblogs.com/songzhenhua/p/16800976.html