利用 monkey pacth 加快 poco 节点定位

阿尔图其网 测试交流1 149字数 6012阅读模式

​ 最近在为公司的 unity 项目接入 poco 进行自动化测试,在进行某一类特定节点的坐标获取时,发现不是一般的慢,代码如下:

last_time = time.time()
nodes = poco(textMatches="Project.*")
print("poco do query time:" + str(time.time() - last_time))
last_time = time.time()
for node in nodes:
node.get_position()
print("poco get all node position time:" + str(time.time() - last_time))

​ 执行结果如下:文章源自玩技e族-https://www.playezu.com/193439.html

文章源自玩技e族-https://www.playezu.com/193439.html

​ 300 多秒。。。够去买瓶酱油了,本人对这个速度根本无法接受。记得官方的加速定位教程中有使用 freeze 函数,让我们试试用 freeze 试试:文章源自玩技e族-https://www.playezu.com/193439.html

last_time = time.time()
nodes = freeze(textMatches="Project.*")
print("poco do query time:" + str(time.time() - last_time))
last_time = time.time()
for node in nodes:
node.get_position()
print("poco get all node position time:" + str(time.time() - last_time))

​ 结果:文章源自玩技e族-https://www.playezu.com/193439.html

文章源自玩技e族-https://www.playezu.com/193439.html

​ 0.006s!?别高兴太早,这块有坑:文章源自玩技e族-https://www.playezu.com/193439.html

nodes = freeze(textMatches="Project.*")
print(nodes[0].get_position())
poco.swipe([0.5,0.5],direction=[0.5,0.7])
#官方文档中该函数用来声明重新获取信息,实测发现只对poco生成的节点有效,freeze生成的节点无效
nodes[0].invalidate()
print(nodes[0].get_position())

​ 滑动后坐标点却不变:文章源自玩技e族-https://www.playezu.com/193439.html

文章源自玩技e族-https://www.playezu.com/193439.html

​ 看来 invalidate() 并未生效,先看看 freeze 干了什么:文章源自玩技e族-https://www.playezu.com/193439.html

def freeze(this):
"""
Snapshot current **hierarchy** and cache it into a new poco instance. This new poco instance is a copy from
current poco instance (``self``). The hierarchy of the new poco instance is fixed and immutable. It will be
super fast when calling ``dump`` function from frozen poco. See the example below.
Examples:
::
poco = Poco(...)
frozen_poco = poco.freeze()
hierarchy_dict = frozen_poco.agent.hierarchy.dump()  # will return the already cached hierarchy data
Returns:
:py:class:`Poco <poco.pocofw.Poco>`: new poco instance copy from current poco instance (``self``)
"""
class FrozenPoco(Poco):
def __init__(self, **kwargs):
hierarchy_dict = this.agent.hierarchy.dump()
hierarchy = create_immutable_hierarchy(hierarchy_dict)
agent_ = PocoAgent(hierarchy, this.agent.input, this.agent.screen)
kwargs['action_interval'] = 0.01
kwargs['pre_action_wait_for_appearance'] = 0
super(FrozenPoco, self).__init__(agent_, **kwargs)
self.this = this
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def __getattr__(self, item):
return getattr(self.this, item)
return FrozenPoco()

​ 按官方文档,结合代码实际上是由于生成了一个静态的 hierarchy 并生产了 PocoAgent 对象,所以后续生成的 poco 对象是结构固定且不可变的,ok,找到对应问题原因了,让我们改进下:文章源自玩技e族-https://www.playezu.com/193439.html

def monkey_freeze(this):
"""
重写freeze方法
"""
class FrozenPoco(Poco):
def __init__(self, **kwargs):
hierarchy_dict = this.agent.hierarchy.dump()
hierarchy = create_immutable_hierarchy(hierarchy_dict)
agent_ = PocoAgent(hierarchy, this.agent.input, this.agent.screen)
kwargs['action_interval'] = 0.01
kwargs['pre_action_wait_for_appearance'] = 0
super(FrozenPoco, self).__init__(agent_, **kwargs)
self.this = this
# 判断当前是否是冻结对象
self.is_agent_freeze = True
self.old_agent = this.agent
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def __getattr__(self, item):
return getattr(self.this, item)
def __call__(self, name=None, **kw):
"""
重写poco类的call方法,用于freeze()后返回结果的回调
"""
if not name and len(kw) == 0:
warnings.warn("Wildcard selector may cause performance trouble. Please give at least one condition to "
"shrink range of results")
# 替换invalidate方法
UIObjectProxy.invalidate = monkey_invalidate
return UIObjectProxy(self, name, **kw)
return FrozenPoco()
def monkey_invalidate(self):
"""
Clear the flag to indicate to re-query or re-select the UI element(s) from hierarchy.
"""
self._evaluated = False
self._nodes = None
# 判断是否是freeze的agent
if self.poco.is_agent_freeze:
# 重新dump
hierarchy_dict = self.poco.old_agent.hierarchy.dump()
hierarchy = create_immutable_hierarchy(hierarchy_dict)
self.poco._agent = PocoAgent(hierarchy, self.poco.agent.input, self.poco.agent.screen)

​ 然后使用猴子补丁:

Poco.freeze = monkey_freeze
poco = UnityPoco(addr, device=dev)
# 或者
# poco.freeze = types.MethodType(poco,monkey_freeze())
freeze = poco.freeze()

​ 再运行刚刚的代码:

​ 完美解决。

​ 完整代码如下:

def monkey_freeze(this):
"""
Snapshot current **hierarchy** and cache it into a new poco instance. This new poco instance is a copy from
current poco instance (``self``). The hierarchy of the new poco instance is fixed and immutable. It will be
super fast when calling ``dump`` function from frozen poco. See the example below.
Examples:
::
poco = Poco(...)
frozen_poco = poco.freeze()
hierarchy_dict = frozen_poco.agent.hierarchy.dump()  # will return the already cached hierarchy data
Returns:
:py:class:`Poco <poco.pocofw.Poco>`: new poco instance copy from current poco instance (``self``)
"""
class FrozenPoco(Poco):
def __init__(self, **kwargs):
hierarchy_dict = this.agent.hierarchy.dump()
hierarchy = create_immutable_hierarchy(hierarchy_dict)
agent_ = PocoAgent(hierarchy, this.agent.input, this.agent.screen)
kwargs['action_interval'] = 0.01
kwargs['pre_action_wait_for_appearance'] = 0
super(FrozenPoco, self).__init__(agent_, **kwargs)
self.this = this
# 判断当前是否是冻结对象
self.is_agent_freeze = True
self.old_agent = this.agent
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def __getattr__(self, item):
return getattr(self.this, item)
def __call__(self, name=None, **kw):
"""
重写poco类的call方法,用于freeze()后返回结果的回调
"""
if not name and len(kw) == 0:
warnings.warn(
"Wildcard selector may cause performance trouble. Please give at least one condition to "
"shrink range of results")
# 替换invalidate方法
UIObjectProxy.invalidate = monkey_invalidate
return UIObjectProxy(self, name, **kw)
return FrozenPoco()
def monkey_invalidate(self):
"""
Clear the flag to indicate to re-query or re-select the UI element(s) from hierarchy.
"""
self._evaluated = False
self._nodes = None
# 判断是否是freeze的agent
if self.poco.is_agent_freeze:
# 重新dump
hierarchy_dict = self.poco.old_agent.hierarchy.dump()
hierarchy = create_immutable_hierarchy(hierarchy_dict)
self.poco._agent = PocoAgent(hierarchy, self.poco.agent.input, self.poco.agent.screen)
Poco.freeze = monkey_freeze
poco = UnityPoco(addr, device=dev)
# 或者
# poco.freeze = types.MethodType(poco,monkey_freeze())
freeze = poco.freeze()
last_time = time.time()
nodes = poco(textMatches="Project.*")
print("poco do query time:" + str(time.time() - last_time))
last_time = time.time()
for node in nodes:
node.get_position()
print("poco get all node position time:" + str(time.time() - last_time))
last_time = time.time()
freeze = poco.freeze()
nodes = freeze(textMatches="^Project.*")
print("freeze do query time:" + str(time.time() - last_time))
last_time = time.time()
for node in nodes:
node.get_position()
print("freeze get all node position time:" + str(time.time() - last_time))

​ PS:由于从 freeze 下通过其 child、offspring 等这类操作获取的节点都是共享的同一个 agent,所以从 freeze 产生的任意一个 poco 对象调用 invaliate 后,其他的 poco 对象都会同步 dump,刷新节点信息时不需要全部都进行 invaliate,例如:

a = freeze("xx")
b = freeze('cc').child('ee')
b.invalidate()
print(a.poco.agent.hierarchy.dump()==b.poco.agent.hierarchy.dump()) #始终为 True

​ 软件测试流程

玩技站长微信
添加好友自动发送入群邀请
weinxin
rainbow-shownow
玩技官方公众号
官方微信公众号
weinxin
PLAYEZU
 
  • 版权提示:本站仅供存储任何法律责任由作者承担▷诈骗举报◁▷新闻不符◁▷我要投稿◁
    风险通知:非原创文章均为网络投稿真实性无法判断,侵权联系2523030730
    免责声明:内容来自用户上传发布或新闻客户端自媒体,切勿!切勿!切勿!添加联系方式以免受骗。
  • 原创转载:https://www.playezu.com/193439.html
    转载说明: 点我前往阅读>>>
    • loneyao
      loneyao 9

      谢谢分享,学习了。

    匿名

    发表评论

    匿名网友
    确定