相對於Android來講,iOS比較封閉。這一點,在設計和評估自動化測試方案的時候感受尤爲強烈。iOS平臺上沒有特別好用的自動化測試工具。蘋果針對iOS提供了UI Automation的Instruments工具,以及相配合使用的Javascript庫,可是使用起來有很大的侷限性。主要問題是必須使用Javascript來編寫測試腳本,不支持其餘語言,很難實現複雜的功能。並且,在一臺mac機上同時只能運行一個Instruments實例,沒法對多個設備同時進行測試。在多數遊戲應用中,UI都不是使用標準控件的,因此不可避免的要使用圖像識別技術。而iOS UI Automation API裏面除了截屏的功能並無提供多少幫助。html
所幸的是咱們找到了UIAHost.performTaskWithPathArgumentsTimeout()方法。這個方法是用來調用外部程序的。巧妙地利用這個方法能夠實現比較複雜的功能。可是我仍然但願測試邏輯能用Python來寫,由於Python用起來至關順手並且有成熟的測試框架。python
要讓UI Automation的Javascript腳本遵從Python腳本的指揮,能夠把Javascript腳本寫成一個服務器,接受來自Python腳本的指令,並調用相應的API完成任務。通訊的任務可使用socket。固然Javascript腳本自己沒法完成這個任務,因此須要調用外部程序來實現。這個外部程序能夠用Python來寫,我稱之爲slave.py,而Javascript腳本就是master.js,由於是master建立的slave進程。固然實際上slave並不聽命於master,master反而要遵從slave從socket得到的指令。ios
這樣一來,只須要寫個驅動層,把API調用包裝一下,經過socket傳輸到slave.py,再經過slave.py的stdout返回到master.js,再經過調用UI Automation API就實現了Python腳本的自動化測試。固然本文沒有涉及不少細節實現問題,留給之後有時間再闡述。服務器
如下是簡化的master.js示例代碼:app
UIALogger.logMessage("Instruments started.") var target = UIATarget.localTarget(); var app = target.frontMostApp(); var window = app.mainWindow(); var host = target.host(); var screenshotPath = "screen"; var python_path = host.performTaskWithPathArgumentsTimeout("/usr/bin/which", ['python'], 1).stdout.replace("\n", ""); if (python_path == "") { UIALogger.logError("python is not found."); } else { while(1) { var result = host.performTaskWithPathArgumentsTimeout( python_path,['InstrumentsSlave.py'], 30); var ins = ("" + result.stdout).split('\n'); if (ins[0] == 'exitApp') break; switch (ins[0]) { case 'tap': var x = ins[1]; var y = ins[2]; target.tap({x:x, y:y}) break; case 'input': var s = ins[1]; app.keyboard().typeString(s) break; case 'captureScreen': target.captureScreenWithName(screenshotPath); break; default: break; } } }