相对于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; } } }