客户端测试我了解的不是很专业,在我的之前的认知里,主要由appium,macaca等构成,都是通过脚本去控制UI的各种操作,抓取元素模拟点击等等。适用场景上,确实比较适合做一些固有case的回归,但是脚本维护的成本略高,不过支持的语言够多,尤其是appium,几乎支持了所有主流语言,我试着写了一下,问题不大,是当固有case发生变化的时候比较惨,代码很多都没法用了。虽然理论上讲固有case是不会发生变化的,但是在业务导向的团队中,不可能百分百保证固有case不发生变化,尤其还是在一个新业务的探索发展阶段。
  我是一个Android DEVER,那么我想了一个够简单的方法:通过AS2.2版本的新特性:Espresso的单元测试录制,让写UT更轻松。但是在我试过之后发现一个鸡肋的问题:录制好的脚本不更改几乎没法用。因为在大型的app上,元素的定位不是那么简单的,而录制的脚本中几乎都用 allOf 来定位元素,显然是不行的,那么维护脚本的成本大了,很多情况下不亚于直接用appium直接去写,所以这个方案我放弃掉了。
  我理想中的方案是:维护脚本成本够低、写test case够简单、可读性够强、如果能Android & iOS共用那更棒,关键的一点: 时间成本要少 。
  于是我邂逅了 Calabash 。
  Calabash上手
  我第一眼相中它的原因是: 它可以用一种类似自然语言的方式编写测试用例 。以往的方式都是TDD,而calabash是BDD,这让我感到很新奇,于是我做了一波尝试。
  先给大家看看我写的第一个固有case(是固有case里简单的一个):
Feature: xxx固有用例
Scenario: 功能:首页
ThenI see"跳过"
WhenI press"跳过"
ThenI press"上海"
WhenI press viewwithid"city"
ThenI see"海外"
WhenI press"海外"
AndI press viewwithid"start_search"
WhenI enter"东京"into input field number1
ThenI press list item number1
ThenI see"东京"
WhenI press"美食"
ThenI see"美食"
ThenI go back
WhenI see"景点"
ThenI press"景点"
ThenI see"景点"
ThenI go back
ThenI press viewwithid"title_image"
ThenIwaitfor5seconds
ThenI press webviewtext"特价机票"
ThenIwaitfor5seconds
ThenI go back
ThenI go back
WhenI scroll down recyclerviewwithid"main_listview"count5
ThenI see"猜你喜欢"
ThenI press viewwithid"root_rl"number1
ThenIwaitfor10seconds
  这个没写过代码的人我相信都看得懂,其实是用我们常规的思维模式去写测试用例。用法非常简单,如果是Mac的小伙伴那简直不要太爽,天生自带ruby,直接用gem去安装calabash可以,这里推荐 安装calabash-android ,其实安装calabash-ios应该是类似的,大家去calabash的 github organization 中找相应平台的repo可以,这里我以Android为例。
  安装完之后,直接用calabash gen生成目录可以,固有的目录都会自动生成,其实主要和我们相关的是 features 目录。
  这里面分为三部分:
  · step宏定义+自定义
  · 各种hooks的support支持
  · 自己写的测试用例,文件名用 .feature 结尾
  很简单,上面的测试case是自己写的测试用例。到这里我突然要告诉大家:calabash只支持ruby。其实如果我不说,估计大家都考虑不到语言,因为从这个case上看,根本看不出语言。不过大家别担心,这里用到ruby的地方无非在一些自定义step和hooks,其他的目前我没发现哪里还需要用了,而且用到的ruby极其基础简单,不需要学,不知道的Google一下完事了。
  后用calabash run命令启动可以,别忘了要有apk或者ipa包,这部分我不细说了,去github看会比较详细。
  其实到这里讲完了,接下来我会分享一下我这两天遇到的坑,也是我觉得用calabash的难点。
  疑难杂症
  难点一:定位元素
  这部分以Android为例,显然很多页面经常会出现id相同的情况,那么我们要通过各种手段定位到的元素。Android极其推荐使用sdk tools目录下的 uiautomatorviewer 进行元素抓取和定位,配合肉眼和calabash console进行定位,三者结合基本上差不多,无非是花时间多少的问题。那么webview部分calabash也是支持的,主要是通过css以及各种条件筛选进行定位,其中text内容匹配用到的多。
  这部分只能慢慢摸索,有经验会快了。
  在定位元素的过程中,会遇到一些宏定义的step不够用的情况,需要自己自定义step。这里给大家看我这两天自定义的几个step:
Then /^I press webview text "([^"]*)"$/do|text|
touch("android.webkit.WebView css:'a' {textContent CONTAINS[c] '#{text}'}")
end
Then /^I press view with id "([^"]*)"number (d+)$/do|id, number|
tap_when_element_exists("* id:'#{id}' index:#{number}")
end
When /^I scroll down recyclerview with id "([^"]*)"count (d+)$/do|id, count|
foriin0..Integer(count)
scroll("android.support.v7.widget.RecyclerView id:'#{id}'",:down)
end
end
  这ruby很简单把,无非是包了一层calabash的api然后识别了一下,没啥技术含量,主要是自己方便用,扩展一下step,这三个自定义的step我在上面的case中都有用到。