去年写了一篇关于《容器化时代对测试的机遇》的文章,提到了一些分布式自动化测试和容器化技术结合的架构设想。但是目前来说,分布式运行并不是难点,亟需解决的问题是针对特殊平台和复杂场景下的测试,例如复杂业务场景下iOS平台的自动化测试。
  移动应用特点是简单易用和UI简洁,以便用户在移动端完成一件事的路径尽可能短。所以一般情况下,我们遇到的iOS APP场景相对于Web应用要简单一些。所以一般情况下iOS自动化测试并不会遇见复杂场景,测试反馈时间短,效率相对较高。对运行环境来说,只需要相应版本macOS系统以及Xcode环境即可。
  但是,对于大型企业的移动应用,例如电商平台、共享出行平台等,牵扯到的主要几个问题:
  1. 大规模的测试用例导致测试反馈时间太长
  说到这个问题,要说到现在主流的移动端自动化测试框架Appium和Calabash。我所经历过的大部分项目,无外乎使用其一。
  但在Xcode 7之后,iOS Simulator变得越来越慢(做iOS的同学们应该都有体会),更不幸的是,在iOS 10、Xcode 8之后,Apple弃用了UIAutomation,导致大量高效、常用的API无法使用。
  并且迄今为止,Appium没有针对iOS 10平台发布一个正式版本的lib和APP,这导致一些用户无法使用inspector定位元素(使用ARC的用户除外),虽然官方建议不要使XPath进行元素定位,但有的时候我们不得不这么做。大杀器是iOS自动化受到Apple的单例限制(一台物理主机同一时间有且仅有一个Instrument)。
  这些种种终导致了iOS自动化测试时间太长,更不用谈及多种iOS设备的兼容性问题了,自动化实现过程成本过高,令大部分组织和团队食之无味、弃之可惜。

  2. 复杂场景无法在一台机器上进行测试
  对于复杂场景的应用来说,我们很难通过现有框架同时在一台物理机上控制多个不同的模拟器,也无法随意的切换到系统级控件去查看APP触发的通知等等。你可以通过一些合法途径使用虚拟化做iOS端的并发测试(切记合法途径)。
  但这样还是逃不掉物理机庞大的开销以及虚拟机的性能损耗问题,抛开这个问题不讲,单从复杂场景来说,例如出行平台,你需要一台机器作为乘客发布订单,还需要多个拥有不同地址定位的车主来测试订单推送优先级等。对于这种复杂场景来说Appium控制起来很难了。

  3. 测试场景需要切换不同APP
  如今很多的APP功能不单单是在应用本身,可能还需要跟系统应用以及其他应用进行交互,例如用户在被测APP中执行某个操作之后,需要检查notification,或者在测试的过程中需要切换无网络环境,从而测试APP的不同行为。
  想到这些复杂场景和各种坑之后,估计打算做iOS测试的同学心里开始打退堂鼓了。下面我们来一步步逐一解决这些问题:
  问题一:解决Instrument单例的限制
  对于这个问题困扰了很久,那业界的互联网公司又是怎么做的呢?有一次看到Uber的Showcase,在一台机器上启动了5、6台模拟器,用不同类型的账号登录(乘客、车主)每个模拟器做不同的行为。由于是在物理机上的对iOS模拟器的操作,速度和性能都得到了很好的保证。他们是怎么解决Instrument的限制呢?
  我们可以通过使用Apple私有API,同时操作不同型号的模拟器,对多个不同的Simulator进行批量化操作,例如启动、重置、安装、运行等操作:

  问题二:解决复杂场景下控制不同iOS模拟器的不同行为
  xcodebuild命令使我们可以把WebDriverAgent运行在我们想要的设备上,但如果使用Apple的命令,还是只能在单个设备上安装运行,之前运行的多台设备都会自动关掉,而只会保留命令中的destination,默认启动8100端口去检测这台设备:
  如果这样的话,那我们之前做的所有工作不没有任何意义了吗?别急,我们已然可以通过Apple提供的资源,对不同的设备启动不同的进程端口进行监听。
  这时我们可以通过curl命令launch我们需要的进行测试的APP,可以轻而易举的拿到当前运行APP的session:
curl -X POST '-H "Content-Type: application/json"' -d "{"desiredCapabilities":{"bundleId":"com.apple.Preferences"}}" http://localhost:8101/session
response:
{
"value" : {
"sessionId" : "94A6580F-1F0F-4411-AC64-3E2525BBA5E1",
"capabilities" : {
"device" : "iphone",
"browserName" : "Settings",
"sdkVersion" : "10.1",
"CFBundleIdentifier" : "com.apple.Preferences"
}
},
"sessionId" : "94A6580F-1F0F-4411-AC64-3E2525BBA5E1",
"status" : 0
}
  同时,对于不同的设备,我们可以通过HTTP server启动inspector来帮助我们进行APP中的元素定位,即使是系统应用:

  问题三:解决不同测试场景需要APP的切换
  有了第二个问题的解决方案,只要执行相似的curl命令,可以拿到不同的APP以及不同的sessionId.

  是时候放弃Appium了?
  通过Uber的Octopus框架以及Appium正在使用的WebDriverAgent, 不难发现此方案的推广速度以及乐观的前景。我们可以使用不同curl命令对不同的Simulator以及APP进行query、tap、typing以及touch id等操作,这与Appium提供的那些我们常使用的API的等价的,并且由于不需要先去调Appium API 而直接去通过WebDriverAgent与元素进行交互,使得测试执行速度上有不同程度的提高,又由于自身强大的控制力以及灵活性,使其可以轻松进行并发操作和复杂业务场景支持,我们只需要把不同的curl命令进行封装,结合各自APP的业务场景便可以轻松完成。
  带来的成本?
  可以说大部分团队没有引入移动端自动化的原因,主要的无外乎编写成本高,UI变化快。个人认为这个方案带来的价值比其带来的成本要大得多。不再需要QA再去学习新的语言来编写脚本,所有与APP元素的交互都可通过HTTP请求来完成,元素信息通过易读的JSON来呈现。我们可以通过任何语言和框架用编写后端自动化测试的方式完成iOS的自动化测试。
  下面通过测试ThoughtWorks的StartKit做一个简单的登录页面的测试Demo。
  总结:
  由于项目因素,我们实践的场景会相对受限,长时间如此可能会影响我们解决问题的思路,我们应该不时的跳出自己工作之外去思考,把简单的事情做的复杂,这样才可以在碰到复杂问题的时候,做的简单。