本文背景:最近花了两三天时间小探索了一下客户端的自动化测试,起因是因为公司项目在提测之前必须自己手点一些固有的测试case,确定没问题才能提测。实在懒得点,就想探寻一下有没有比较简单的办法解决这个问题。
技术选型
客户端测试我了解的不是很专业,在我的之前的认知里,主要由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里最简单的一个):
1 | Feature: xxx固有用例 |
这个没写过代码的人我相信都看得懂,其实就是用我们常规的思维模式去写测试用例。用法非常简单,如果是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:
1 | Then /^I press webview text "([^\"]*)"$/ do |text| |
这ruby很简单把,无非就是包了一层calabash的api然后识别了一下,没啥技术含量,主要就是自己方便用,扩展一下step,这三个自定义的step我在上面的case中都有用到。
难点二:流程控制
Feature
我们在上面的case中可以看到有Feature
的标识,这是calabash的一个控制单元(我的理解),每运行一个Feature,apk都会卸载重装,保证每次都是全新无副作用的应用。
Scenario
这个标识是囊括在Feature中的,一个Feature可以有很多个Scenario,运行每个Scenario的时候应用只会退出再重进,不会卸载再重装。
Hooks
在feature/support包下,我们会看到这么几个ruby文件:
- app_installation_hooks.rb
- app_life_cycle_hooks.rb
- env.rb
- hooks.rb
可以看到,基本上都是hook用的,我们看一个简单的app_life_cycle_hooks.rb
理解理解:
1 | require 'calabash-android/management/adb' |
这是默认就生成好的,从字面意思上看,就是app生命周期的hook,这里可以看到,在主要用到了Before
和After
关键字进行操作,这个显然很容易就看懂了,于是我自己写了一个在每个step执行之后都等待2秒的hook,下面的代码写在hooks.rb
中(这个文件默认生成是空的):
1 | require 'calabash-android/calabash_steps' |
很容易对吧?关于这部分想多了解的可以看cucumber wiki中的Hooks部分。
总结
首先,calabash是我最后唯一选中的客户端自动化固有case的方案。这里说下原因:
- 脚本维护成本很低,就算固有case发生变化,也可以花很少的时间迅速更改脚本
- 我们的业务固有case数量不大,操作主要涵盖的部分calabash都可以完成,编写脚本的成本低,无语言障碍
- 可读性非常强,代码简单易懂,任何一位DEVER都可以零成本上手,有Mac的连装环境都差不多省了
- 小范围组内使用成本低,坑有但是并不大,都可以解决,某些机型不兼容问题直接用genymotion跑就行了,最简单(主要还是固有case不复杂)
- Android & iOS都可以使用
- 玩起来很有意思,对于我这种懒人来说是福音
估计还有一些高级的玩法我还不会,不过目前这些都够我写一些固有case了,目前我们组内将会对这个方案进行评估,没啥问题就组内小范围用了,如果有感兴趣的朋友欢迎一起讨论唷。
谢谢大家。