一招讓 IOS 自動化化快的飛起


前言

最近在做IOS自動化測試,IOS的Appium環境都配置OK,Demo腳本運行沒有問題,多開執行沒有問題,IOS安卓統一平台調度集成沒有問題,可以進行自動化測試。
課時真正執行用例時發現個嚴重問題:執行速度過慢,慢的像中國男足,Appium的執行log滿屏刷,找元素像男國足球場一樣騷,一個像無頭蒼蠅滿場跑,一個有模有樣的一輪又一輪的查找,就是命中不了。
很是蛋疼,一直疼了好幾天,都有放棄的念頭了。

調查

Xcode9 SDK不再支持snapshot功能了,沒有snapshot功能就無法獲取page_source。而從Appium1.6.5+后,Facebook用WDA snapshot, 相比於Xcode SDK的snapshot, WDA snapshot在生成page source的時候包含了一個之前沒有的屬性, 也就是visibility屬性。計算元素的visibility在XCTest中是非常痛苦和昂貴的操作。
xpath 好像每次查找時都是重新生成一棵樹,WDA需要額外的努力來實施XPath查詢,這會嚴重影響查找時間遍歷整個元素樹,生成一個 xml 數據,然后再做 xpath 查找。遍歷和在 xml 中進行 xpath 查找都相當耗時。論壇比較多的說法是查找元素策略的性能從高到低排列如下:Class Name>Accessibility Id>Link Text>Predicate>Class Chain>XPath
但是以上各種方式試過了,也沒有讓我的用例快起來。

大坑

搜索了很多帖子,很多人都是反映IOS自動化速度太慢。但是都沒提怎么解決。由於不想改現在共通的滑動和安卓手機按鍵操作的代碼,沒有java-client升級,保留當前5.0.4的版本,沒有想到掉這么個大坑里,搞了兩三天百撕不得騎姐。
和py最新庫執行相同用例后的速度對比后才發現,可能是jar包的原因。升級java-client版本5.0.4-->6.1.0,升級前來執行6分鍾左右的下單用例,升級后2分鍾(包括人為設置的等待時間)不到就執行完成了。
更換版本后真的快的飛起啊,比安卓用例執行更快了。
這里說一下我的環境配置,方便速度慢的同學參考:

  • Xcode:9.4.1
  • Appium:1.8.1
  • 模擬器:11.4
  • java-client:6.1.0(非常重要,和5比速度差的不是一個級別的)

元素定位優化策略

  • 盡量不使用xpath

長的Xpath定位可以使用謂詞定位,Accessibility Id定位等來逐步縮小搜索的范圍,曲線救國。如下例:

IOSElement inputEL = driver.findElementByXpath("//XCUIElementTypeNavigationBar[@name='LVMMTabBar']/XCUIElementTypeStaticTex");

轉換成

IOSElement barEL = driver.findElementByIosNsPredicate("type == 'XCUIElementTypeNavigationBar' AND name == 'LVMMTabBar'");
IOSElement inputEL =barEL.findElementByIosNsPredicate("type == 'XCUIElementTypeStaticText'");

但是由於有些復雜的Xpath很難完全將Xpath的定位方式轉換成Class Name,Accessibility Id,Predicate或者classChain定位,所以Xpath還是不能拋棄的。
只能說盡量不使用xpath特別是頁面元素比較多的時候。不到萬不得已,盡量不用(頁面元素少,速度還可以接受時,可以不轉換,靈活運用,轉換前后性能自行比較一下)。

  • 盡量使用高性能查找

各種查找元素策略的性能從高到低排列如下(未一一按時間來具體驗證):
Class Name
AccessibilityId
Link Text
Predicate
classChain
XPath

使用方法這里就不一一贅述了。很多同學估計對謂詞不了解,也是java-client版本5.0.4以及以后版本才可以使用的,用下來感覺蠻好的的。
可以看一下全網最好的謂詞掃盲貼---->謂詞大法傳送門

  • 盡量使用精確查找

例如通常我們知道"name='https://testerhome.com'"的元素只有一個時,盡量使用

IOSElement niubiEl = driver.findElementByIosNsPredicate("type == '最牛逼的測試交流論壇' AND name == 'https://testerhome.com'");

不要使用

List<IOSElement> niubiEls = driver.findElementsByIosNsPredicate("type == '最牛逼的測試交流論壇' AND name == 'https://testerhome.com'");
IOSElement niubiEl = niubiEls.get(0);

同類的findElementByAccessibilityId和findElementsByAccessibilityId等

通常情況下findElements方法會遍歷這個頁面去找出所有匹配查詢的頁面元素,而findElement花費更多的時間, 因為findElement不會,而是僅僅返回第一個匹配查詢的元素(機器是不會喊累,但也請不要讓人家干無用功)。

  • 盡量少通配符

很多人喜歡封裝,但是過度封裝,使用很多通配符,以達到萬能找元素的效果,但是可能帶來的后果就是執行效率低。例如:

List<IOSElement> comnEls = driver.findElement("//*[contains(@name,'" + targetParam+ "') or contains(@label,'" + targetParam+ "') or contains(@value,'" + targetParam+ "')]");

調用是簡單了,只需傳個參數targetParam就好了,但是這需要掃描每個UI元素的所有name,lable,value屬性(上面屬性還可以繼續加,達到萬能匹配), 無疑這是極度低效的。
對於爬蟲來說,可能需要爬取更多相關的東西,但是我們自動化來說,目標很明確。老老實實的的使用

IOSElement niubiEl = driver.findElementByAccessibilityId("type == '最牛逼的測試交流論壇' AND name == 'https://testerhome.com'");

更高效。

  • 盡量減少和服務的通信

    if (driver.isElementExist("//XCUIElementTypeButton[@name='未選擇']"))
    {

    driver.findElement("//XCUIElementTypeButton[@name='未選擇']").click();
    }

    上述如果存在時,則會查找兩次(也許例子不恰當)。不如把邏輯放在自己代碼里。

    IOSElement selEl = driver.findElement("//XCUIElementTypeButton[@name='未選擇']");
    if(selEl != null)
    {
    selEl .click();
    }

升級后的小問題

升級后一些方法無法正常使用或者過時了。
點擊升級前

new TouchAction(driver).tap(x , y).perform();

點擊升級后

new AndroidTouchAction(driver).tap(PointOption.point(x , y )).perform();
安卓和IOS分開了
new IOSTouchAction(driver).tap(PointOption.point(x , y )).perform();

滑動升級前

new TouchAction(driver).press(beginX, beginY).waitAction().moveTo(endX, endY).release().perform();

滑動升級后

new AndroidTouchAction(driver).press(PointOption.point(beginX, beginY)).waitAction().moveTo(PointOption.point(endX, endY)).release().perform();
安卓和IOS分開了
new IOSTouchAction(driver).press(PointOption.point(beginX, beginY)).waitAction().moveTo(PointOption.point(endX, endY)).release().perform();

Android按鍵操作
升級前

driver.pressKeyCode(AndroidKeyCode.HOME);
driver.pressKeyCode(AndroidKeyCode.BACK);
.
driver.pressKeyCode(AndroidKeyCode.KEYCODE_NUMPAD_9);

升級后

androidDriver.pressKey(new KeyEvent(AndroidKey.HOME));
androidDriver.pressKey(new KeyEvent(AndroidKey.BACK));
.
androidDriver.pressKey(new KeyEvent(AndroidKey.NUMPAD_9));

后記

升級版本后總於解決了執行龜速的問題,蛋也不疼了,如同夢中看到國足秒殺歐冠一樣的快意,看着執行速度快的飛起,簡直要GC了。
這些遇到的一些小坑,總結分享一下。大神輕噴,分享給那些和我一樣low 的人(看到很多人Q群里問環境搭建,Demo跑不了,求視頻,還有很多付費培訓廣告),我感覺分享還是很有必要的,畢竟大神麼就你們幾個。

關於IOS執行速度,你有什么騷操作,歡迎一起交流探討。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM