Calabash Calabash 学习经验小结

apogee · 2014年07月24日 · 最后由 糖糖 回复于 2017年05月17日 · 2922 次阅读
本帖已被设为精华帖!

引子

介绍一下自己几个月以来学习 Calabash 的经验,从一个对 Calabash 完全不了解的新手开始,到用 calabash 写过一个 iPad 项目,一个 Android 平板项目,外加一个 iPhone 项目的自动化测试,双手已经沾上一些 Calabash 的味道。好比一个小兵,端起枪上过战场,打过两场小规模战斗,长了点见识之后仍然是一个小兵,从一个完全的新手,变成一个尝过一点 Calabash 味道的新手。废话少说,下面介绍一下自己学习 Calabash 的经验:

安装

最开始的时候,安装一个稳定的版本组合很重要。

具体的安装步骤,请参考官方文档。这里只是提醒一下,对于 Calabash 来说,不同的版本组合会碰到不同问题,至少我自己一开始碰到不少问题,经过测试的版本组合才能推荐给其他人,才能升级 CI 环境。

对于一个新手来讲,选择错误的版本组合,意味着你碰到奇怪错误的机会增加。而刚开始就不能顺利上手,而是去研究 Calabash,OS,iOS,SDK, 模拟器等各种版本兼容性问题是一件非常恼人的事情。虽然排错是很好的学习方式,但一开始就碰到兼容性问题可能会降低你的学习热情,以为 Calabash 只是一个不成熟的玩具,其实不然。

入门

如果你刚接触 Calabash, 要看的东西并不多,下面这两个地方仔细看一遍就足够了。
iOS:
https://github.com/calabash/calabash-ios/wiki/_pages
Android:
https://github.com/calabash/calabash-android
其中的两个章节:03.5 Calabash iOS Ruby API 和 05 Query syntax, 在开始写脚本的时候会不断回头参考。

上手

下面假设你的环境没问题了,接下来该找个 iOS 或 Android 的具体项目开始写测试,光看懂 Github 上那个简单的 demo,理解大致的原理远远不够, 真正动手写 Calabash 脚本的时候,你会碰到很多问题。具体来说,刚一开始你最常碰到的问题是:

  1. 如何定位元素
  2. 为什么运行结果有时候不稳定

对于第一个问题,如果你的 app 比较简单,元素的 id, name 属性齐全,可能问题不大。如果能看懂并修改源代码,或者让开发人员帮你补上帮助识别元素的属性最好。如果这个方法行不通,很多时候识别一个元素有很多种写法,99% 的可能你能找到替代的写法。这个时候是你熟悉 Calabash console, 熟悉 Query syntax 的最好时机。启动 Calabash console, 定位你想要的元素,尝试使用各种 Query syntax 定位元素。

相对于 Web 浏览器上的开发工具,Calabash 识别元素的方法还比较 “原始”,需要用 start_test_server_in_background 打开 console, 然后利用 query 去搜索想要的元素,比在 Web 浏览器上定位一个元素麻烦很多。calabash-ios 提供了一个 flash 方法,用来确定元素找得是否准确,但 calabash-android 没有提供对等的方法,所以不能用元素高亮来定位。

值得一提的是,在我测试的 Android 应用上面,通常 id, name 这样的属性不唯一,利用 id 或 name 去 query, 往往会返回一组 id 相同的元素,其中大部分的 x,y 坐标不在可见范围内,这种情况需要利用坐标继续过滤返回结果。一个比较好的方法是自己写一个类去继承 Calabash::ABase,然后自定义一个 query(uiquery, *args) 方法,过滤掉 x,y 坐标不在可见范围的元素。

对于第二个问题,用 Calabash 写 UI 自动化集成测试和回归测试,如果运行结果不稳定的话价值就不大了。这个时候是练习使用 trait, await, wait_for, element_exists 等方法,熟悉 Calabash API 的最好时机。
写 Calabash 测试,或者写其他任何 UI 测试的时候,直觉上想消灭所有 sleep 语句。但完全消灭 sleep 并不简单,尤其对于 calabash-android 来说, 目前没有 wait_for_none_animating 方法, 需要自己寻找等待策略,但这个时候也是积累经验的最好时机,多尝试一些 wait_for 和 element_exists 方法,让你的测试脚本变得更稳定。

书写易于维护的测试

如果进行到此一切顺利,你已经对元素定位,提高脚本的稳定性有了一些经验,接下来你可以写很多代码开始做项目了。

当你的代码量不断增加,你会开始考虑如何组织你的测试代码,如何写易于维护的代码这个大问题。Page Object Model 是一个不错的选择,也是 Calabash 官方推荐的方式。关于 Page Object Model,网上已经有很多讨论,以后有时间的时候可以另开一贴讨论。

除了 POM 以外,有些其他话题可以先讨论一下:

避免嵌套使用 macro 语法
完全不使用 macro 难免会写很多重复的 steps, 但 macro 嵌套使用会大大增加维护成本,代码也将变得不易读。建议:可以使用 macro, 但一定避免嵌套使用。

避免过于琐碎的 cucumber story
比如一个 Successful login scenario 可以像下面这样写:

Given I am on login screen
And I input my username
And I input my password
And I click on "Login" button
Then I should login successfully. 

单独写这样一个 login scenario 没关系,但是几乎每个 scenario 都需要 login, 因此需要再写一个简短版本的 login 语句。
上面只是一个简单的例子, Cucumber 可以有两种书写风格 imperativedeclarative,前一种书写过多细节,后一种隐藏细节,两种风格任意一种走向极致都不好,但书写过于具体的步骤肯定不推荐,可以阅读《The Cucumber Book》中的第六章 “When Cucumbers Go Bad” 避免写出琐碎且不易为维护的 story。

跨平台测试的代码如何组织
通常一个移动 app 会有 iOS 和 Android 两个版本,功能界面和用户体验在两个平台上大致相同,因此测试的 features 和 scenarios 会有大部分重叠。不仅如此,写测试脚本通常要为两个平台写很多辅助代码, 比如调用 backend service, 访问数据库,以及一些自定义辅助方法很可能在两个平台共享。从代码重用的角度,有理由把 iOS 和 Android 的测试代码放在一起,比如官方提供个一个组织跨平台代码的例子:https://github.com/calabash/x-platform-example

然而,把 Android 和 iOS 的测试代码放在一起也有一些很明显的缺点:

  1. 不方便搜索,即使是自己写的代码,当 file 和 folder 的数量不断增加,调试代码的时候经常需用 editor 进行全目录搜索。将 iOS 和 Android 代码放在同一目录下,使每次搜索返回两个结果:一个在 ios 目录里面,另一个在 android 目录里面,不小心容易点错,而去编辑另一个平台的代码。
  2. 对于两个平台共用部分的代码,每做一次修改,需要考虑两个平台上的结果,需要在两个平台分别验证结果。
  3. 不方便运行单个测试从而不方便调试。尽管 Cucumber 提供了 profile 机制,可以为 iOS 或 Android 加载不同的目录,但每运行一个测试都需要指定 profile, 是不必要的负担。
  4. 两个平台的产品也会有差异,有些 test case 不会完全相同,在同一个 feature 里面可能会分别打上 @ios, @android, 或@common这样的 tags, 当 scenarios 的数量开始增加,利用 tag 机制区分同一个目录,甚至是同一个文件下两个平台的代码,不是一个好方法,间隔时间稍微久一点就容易混淆,因此这样的 tagging 方式不建议使用。

总之,要不要放在一起要看测试代码的规模,两个平台上实现的异同,共用代码的数量,多少人共同开发维护脚本来决定。个人建议:对于比较简单的项目,可以把两个平台的测试代码放在一起,否则还是分开更好。

结尾

最后,用一个采用 PMO style 写 Calabash 测试可能遇到的一个小错误作为结尾:
下面这段代码来自网上(http://rubygemtsl.com/tag/calabash-android/

class WordPressApp < DroidPress

def welcome_screen
  @welcome_screen ||= page(WelcomeScreen)
end

def login_screen
  @login_screen ||= page(LoginScreen)
end

def home_screen
  @home_screen ||= page(HomeScreen)
end

end

welcome_screen 方法第一次被调用的时候从 page 方法返回一个 object, 之后的调用直接返回@welcome_screen,经常写 ruby 代码的同学会习惯这样写,但是上面这段代码当 welcome_screen 更新后结果就不一定准确了,因此要写成下面这种 “低效” 的方式,每次使用 welcome_screen 都要从 page() 那里再次获取

class WordPressApp < DroidPress

def welcome_screen
  page(WelcomeScreen).await
end

end

实际上,对于通过 UI 进行测试的代码,慢的地方一般不在 ruby 写法是否高效,即使每次都从 page() 方法获取 object 和直接返回@welcome_screen完全感觉不到区别。

没想到会写这么多, 抛砖引玉,欢迎各位指教。

共收到 9 条回复 时间 点赞

你好,你说的安装一个稳定的版本组合很重要,那根据你的经验,哪些组合是能正常运行的呢,我是一个新手,刚接触,在 windows 下跑的,试过很多版本的组合,都会报错 “D:/ProgramFiles/Ruby193/lib/ruby/gems/1.9.1/gems/calabash-android-0.5.1/lib/calabash-android/helpers.rb:105:in `scan': invalid byte sequence in GBK (ArgumentError)”,然后根据这个错误,我装了 2.0,因为 2.0 的默认系统编码是 “UTF-8”,结果还是遇见了上面的问题,现在有点束手无策的感觉,因为上网查了很多资料,都没能解决问题。所以就在想是不是你描述的版本的组合不好,会遇见很多奇怪的问题。

#1 楼 @doufuli010 安装 powercmd,然后在 PowerCMD 里面重新进行执行 try 下

#1 楼 @doufuli010 Ruby2.0 的默认源文件编码是 utf-8, 但不一定每个文件都按照 utf-8 去读,可能某个文件按照 GBK 编码读取所以出错。找到那个源文件,最上面加上 # encoding: utf-8 试试看。

谢谢各位的耐心解答,2 位说的方法我都 try 了 3 次以上,但是都没有用,所以我直接放弃 windows 了,安装了 fedora,搭建了一套 linux 环境,现在已经能够正常运行了,那个问题还是没有解决,很诡异。

请问 Calabash console 如何启动?

#1 楼 @doufuli010
我也在 windows 下安装 calabash-android,
在英文版 Win7 下安装,能正常运行,
在中文版 Win7 下安装,碰到你相同的问题:
helpers.rb:105:in `scan': invalid byte sequence in GBK (ArgumentError)”

然后怀疑是 cmd 的缺省编码搞的鬼,
英文和中文 Windows 下,分别查看 cmd > 属性 > 选项,
英文 Win7:当前代码页:65001 UTF-8
中文 Win7:当前代码页:936 GBK
答案在这里:http://blog.sina.com.cn/s/blog_628e2ab30101ajcg.html
中文 Win7 的 cmd 下输入 chcp 65001,然后你就看到 cmd > 属性 > 选项 > 65001 UTF-8
然后你的问题就解决了。

@htmlbiji 恩恩 谢谢啦 我一直在 linux 上实践 现在终于能在 windows 上跑了 太开森了

楼主,我才开始学习 calabash-android,请帮忙看看出现这个问题是怎么回事嘛v^ v^ ……
invalid byte sequence in UTF-8 (ArgumentError)

你好,请问还在研究 calabash 吗,我想问下你知道如何修改 calabash-android-server 中的源码然后应用到我的项目中去么

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册