Appium - 如何提高查找元素的性能


本文基于的Automation Engine是XCUITest for iOS。


iOS11发布以后,我意识到我不得不升级了, 毕竟让用例继续在iOS9上执行并不是一个好的选择。于是,我花了一段时间,升级到了python3 + Appium1.7.2 + Xcode9.2, 当然过程不会像我描述的那样简单。当我看到用例终于可以运行在iOS11.2上时,我觉得一切都是值得的。可是,我遇到了一个新的难题,用例的执行速度比原来慢的多得多。 一个普通的用例都需要耗费300秒左右的时间,显然这对测试时间和测试稳定性来说都是难以接受的。而最终我完美的解决了这个问题, 于是便有了这篇文章。严格来说,本文不能算是原创,只是重新组织了下自己和别人的心得。


一番搜索,我找到了两个导致用例执行速度突然降低的可能原因:

(1)XCTest on Xcode9 SDK does not perform snapshotting anymore by default. Apple has removed it for performance reasons. However, it is also not possible to get the page source tree without it. So WDA team had to reenable snapshots support in XCTest preferences as a workaround. That is why the stuff is slower on iOS 11 in comparison to iOS 10/9.
(2)Appium Version 1.6.5+ is different, because it includes WDA snapshot, where generated source includes visibility attribute. Previously it was not included because of performance and stability reasons.Element visibility calculation in XCTest is quite painful and expensive operation. And, since xpath lookup is not supported natively, it is necessary to build the whole UI hierarchy tree (which is more or less fast) and calculate attributes for each node (which is the slowest operation, especially for visible attribute, and heavily depends on the actual count of nodes in the tree/accessibility elements). Then we execute xpath query on this generated document (fast operation) and match the found item(s) to the existing accessibility object(s) (was slow before, but now the performance of this operation is quite OK).

简单来说, 其实就是Xcode9 SDK不再支持snapshot功能了,但是没有snapshot功能就无法获取page_source, 所以WDA team决定自己启用snapshot。而从Appium1.6.5+后,就开始包含WDA snapshot, 相比于Xcode SDK的snapshot, WDA snapshot在生成page source的时候包含了一个之前没有的属性, 也就是visibility属性。计算元素的visibility在XCTest中是非常痛苦和昂贵的操作。


扯了这么多,还是言归正传吧。 准确的说,本文是介绍如何高效的查找页面元素, 换句话说,我们就是要让get_element(s)方法的执行时间达到最短, 而这其实是和定位方式息息相关的。

1. 选择最高效的查找策略(定位方式) 

各种查找元素策略的性能从高到低排列如下:
Class Name
Accessibility Id
Link Text
Predicate
Class Chain
XPath

几乎每个做过Web UI Automation(selenium webdriver)的人都知道XPath的查找性能是最低的。但很少有人会彻底放弃XPath, 一方面是因为XPath足够强大,另一方面也是因为这种程度的性能损耗我们无法真正感觉得到。但在XCTest中,XPath有时候会慢到你难以忍受。 因为原生的XCTest并不支持XPath,WDA需要额外的努力来实施XPath查询,这会严重影响查找时间。如果不是没有其它选择,我们应该尽量避免使用XPath。

PS: 
(1) 我们几乎无法100%的将使用XPath轴的定位串转换成Predicate或者Class Chain(但变通的方法通常都有)。
(2) 避免直接调用page source。
(3) 当页面包含非常多的页面元素时,XPath查找的性能也会相应降低。而获取Page source的性能会降低到无法忍受的程度(甚至有可能造成异常)。

2. 缩小搜索的范围
table = driver.findElement(By.accessibilityId('table'));
text = table.findElement(By.predicate('type == "XCUIElementTypeTextField" AND visible == 1'))
如果在搜索范围内的UI元素越多,那么搜索花费的时间就会越多, 而默认情况下搜索范围是整个页面。通过缩小特定元素的查询范围能够一定程度上优化查找元素的性能,特别是当多个元素的查找都将在同一个根元素下执行的时候。这种策略可以帮助我们提高查询效率。


3. 如果你只想要一个元素,那就不要查询多个元素
table = driver.findElement(By.className('XCUIElementTypeTable'))
通常情况下findElements方法会比findElement花费更多的时间, 因为findElement不会遍历这个页面去找出所以匹配查询的页面元素,而是仅仅返回第一个匹配查询的元素。

4. 避免太过通用的匹配方法
By.xpath('//*[@*="1"]/parent::*') 

太过通用的匹配方法就像上面使用的//*和@*="1", 这需要扫描每个UI元素的所有attributes, 无疑这是极度低效的。

如果修改成By.xpath('//XCUIElementTypeCell[@name="1"]/parent::XCUIElementTypeTable'),那查找性能就会提高许多。但是我们永远也不要忘记第一条: 尽量避免使用XPath, 我们转换成如下的classChain将会更好:

By.classChain('**/XCUIElementTypeTable[$type == "XCUIElementTypeCell" AND name == "1"$]')



你可能感兴趣的:(Appium,自动化测试)