使用calabash测试开源中国Android客户端

Calabash-android是支持android的UI自动化测试框架,前面已经介绍过《中文Win7下成功安装calabash-android步骤》,这篇博文尝试测试一个真实应用:开源中国客户端。目的是和大家一起学习calabash测试工具。

测试环境与源码准备

先介绍一下oschina.net

<www.oschina.net>

在此输入图片描述

oschina除了有网站,还有三大平台手机客户端:

http://www.oschina.net/app

客户端下载

客户端已经开源!

那么开源可以用来做什么呢?

我正在学用calabash-android,得找到一个合适的待测app,平时手机上开源中国这个app用的蛮顺手了,所以就选它了,在此特别向开源中国的开发工程师致谢!

环境准备:ADT+calabash-android

可以参考:
中文Win7下成功安装calabash-android步骤

下载oschina/android-app源代码

首先到 http://git.oschina.net/oschina/android-app

在此输入图片描述

以下两种下载源代码方式的方式都可以:

  1. 可以直接点击”下载zip“
  2. 复制git仓库url: https://git.oschina.net/oschina/android-app.git ,然后在Eclipse/ADT中打开Windows > Open Perspective > Other... > Get Resporsitory Exploring,clone源代码

导入到ADT中后,源代码如下:

在此输入图片描述

在adt-bundle-20140702中编译运行oschina/android-app的几个问题

问题1: adt-bundle-20140702的API版本是20,所以要修改project.properties:
target=android-15 改成 target=android-20

问题2: 源代码是使用了已作废的class: android.webkit.CacheManager
oschina-android-app/src/net/oschina/app/AppContext.java中使用了android.webkit.CacheManager
所以要把相关代码禁掉:

61行:

//import android.webkit.CacheManager;

1503到1509行:

// File file = CacheManager.getCacheFileBaseDir();
// if (file != null && file.exists() && file.isDirectory()) {
// for (File item : file.listFiles()) {
// item.delete();
// }
// file.delete();
// }

问题3:Run As Android Application报错:Installation error: INSTALL_FAILED_VERSION_DOWNGRADE
原因是:手机已经装了一个开源中国的1.7.7.0版本,而ADT要下载的是1.7.6.9版本,Android系统不允许安装一个比已安装版本更旧的版本,所以从手机上卸载已有的1.7.7.0版本就可以了。

ADT编译并上传oschina/android-app到手机

Run As Android Application > 选择连接到电脑Usb的手机 > OK
在此输入图片描述

calabash测试步骤

先确认oschina/android-app声明了访问网络的权限

oschina/android-app项目的AndroidManifest.xml中应该如下行:

在oschina/android-app根目录中创建calabash目录

在命令行下进入oschina/android-app的源代码根目录:

D:\git\oschina>cd android-app

D:\git\oschina\android-app>dir
Volume Serial Number is 9823-AB19

Directory of D:\git\oschina\android-app

2014/09/01 20:26

.
2014/09/01 20:26 ..
2014/09/01 20:21 783 .classpath
2014/09/01 20:21 .git
2014/09/01 20:21 64 .gitignore
2014/09/01 20:21 822 .project
2014/09/01 20:21 .settings
2014/09/01 20:21 10,829 AndroidManifest.xml
2014/09/01 20:21 assets
2014/09/01 20:42 bin
2014/09/01 20:26 gen
2014/09/01 20:21 libs
2014/09/01 20:21 18,092 LICENSE.txt
2014/09/01 20:21 1,424 proguard.cfg
2014/09/01 20:41 563 project.properties
2014/09/01 20:21 4,183 README.md
2014/09/01 20:21 res
2014/09/01 20:21 src
8 File(s) 36,760 bytes
10 Dir(s) 133,131,993,088 bytes free

D:\git\oschina\android-app>

创建calabash目录:

D:\git\oschina\android-app>mkdir calabash

创建cucumber skeleton:

D:\git\oschina\android-app>cd calabash

D:\git\oschina\android-app\calabash>calabash-android gen

----------Question----------
I'm about to create a subdirectory called features.
features will contain all your calabash tests.
Please hit return to confirm that's what you want.
---------------------------

----------Info----------
features subdirectory created.
---------------------------

D:\git\oschina\android-app\calabash>dir
Volume Serial Number is 9823-AB19

Directory of D:\git\oschina\android-app\calabash

2014/09/01 21:54

.
2014/09/01 21:54 ..
2014/09/01 21:54 features
0 File(s) 0 bytes
3 Dir(s) 133,131,988,992 bytes free

D:\git\oschina\android-app\calabash>

编辑 D:\git\oschina\android-app\calabash\features\my_first.feature:
初始内容:

Feature: Login feature

Scenario: As a valid user I can log into my app
When I press "Login"
Then I see "Welcome to coolest app ever"

第一行Feature: XX,第二行 Scenario: YY是给人读的,所以随便填写什么中文英文内容都可以
关键内容是第三行When I press ..和第四行Then I see .., 这是给Cucumber软件识别的。
When后面跟动作语句,Then后面跟内容检查语句

先尝试如下改动:

Feature: 启动开源中国

Scenario: 启动应用后,能看到软件版本更新信息
Then I see "软件版本更新"

%windir%\system32\cmd.exe /k chcp65001&&ansicon 启动ansicon,
运行calabash-andriod run
D:\git\oschina\android-app\calabash>calabash-android run D:\git\oschina\android-app\bin\oschina-android-app.apk

在此输入图片描述
测试失败,原因是Then的默认等待时间只有2秒,开源中国app的启动时间比较长。
ansicon中未能显示中文:"软件版本更新",这个后面补充中有描述。

按照 https://github.com/calabash/calabash-android/blob/master/ruby-gem/lib/calabash-android/canned_steps.md的指导,可以指定等待几秒:

Feature: 启动开源中国

Scenario: 启动应用后,能看到软件版本更新信息
Then I wait for 10 seconds
Then I see "软件版本更新"

在此输入图片描述

手机上看到的开源中国启动后画面:

在此输入图片描述

按钮“立即更新”为什么是红色的?以后再解决。

到此步为止,calabash测试开源中国Android客户端的环境已经建立完毕,接下去同学们就可以欢快的尝试canned_steps.md里的各个预定义步骤了。

我也会继续完成这个测试用例,大家一起共同进步!

补充解决问题:calabash测试输出中不能显示中文

解决方法:
ansicon启动时,不要用chcp 65001设置为UTF-8编码,
%windir%\system32\cmd.exe /k ansicon 启动ansicon,然后运行calabash:

在此输入图片描述

试用calabash预定义指令

试用 press, don't see, screenshot

运行前,先把D:\git\oschina\android-app\calabash下的screenshot_*.png都删了,避免搞不清楚旧图和新图。

不解释,看脚本和截图:

Feature: 启动开源中国

Scenario: 启动应用后,能看到软件版本更新信息
Then I wait for 5 seconds
Then I take a screenshot
Then I see "软件版本更新"
Then I see "以后再说"
When I press "以后再说"
Then I don't see "以后再说"
Then I take a screenshot

在此输入图片描述

在此输入图片描述

calabash脚本生成的手机截图:

在此输入图片描述

在此输入图片描述

到系统设置中启用左右滑动,为了后面测试手势指令

Feature: 启动开源中国

Scenario: 启动应用后,能看到软件版本更新信息
Then I wait for 5 seconds
Then I see "软件版本更新"
Then I see "以后再说"
Then I take a screenshot
When I press "以后再说"
Then I don't see "以后再说"
Then I see "最新资讯"
Then I take a screenshot
Then I press the menu key
Then I see "系统设置"
Then I take a screenshot
When I press "系统设置"
Then I see "已关闭左右滑动"
Then I take a screenshot
When I press "已关闭左右滑动"
Then I see "已启用左右滑动"
Then I take a screenshot
Then I go back
Then I see "最新资讯"
Then I take a screenshot

在此输入图片描述

在此输入图片描述

在此输入图片描述

手势:swipe right = 翻看右边的内容

这个right比较难理解,是不是解释为“翻看右边的内容”比较容易记住。
Feature: 启动开源中国
...
Then I swipe right
Then I see "问答"
Then I don't see "最新资讯"
Then I take a screenshot

在此输入图片描述

在此输入图片描述

scroll up 运行失败

Then I scroll up

在此输入图片描述

找不到android.widget.ScrollView元素,看样子oschina的可滚动区域不是用标准控件实现的。

通过id找到控件并做相应操作

接下去我要搜索包含"calabash"的博客,

首先要点击首页右上角的放大镜图标:

放大镜图标

这个图标上没有text可以识别,所以必须到首页布局文件mail.xml中找到搜索图标的id,

ADT中打开文件:D:\git\oschina\android-app\res\layout\main.xml

main.xml

点击搜索图标,右上角的Outline指示搜索图标在main_header.xml中定义。

双击 include-main_header,ADT打开main_header.xml:

search-id

点击搜索图标,右边的Outline和Properties区都指示搜索图标的id是main_head_search,控件类型是:ImageButton

接下去在calabash中可以用id点击搜索图标了:

Feature: 搜索包含calabash的博客

Scenario: 启动应用后,能搜到包含calabash的博客
Then I wait for 5 seconds
Then I see "软件版本更新"
Then I see "以后再说"
Then I take a screenshot
When I press "以后再说"
Then I don't see "以后再说"
Then I see "最新资讯"
Then I take a screenshot
When I press view with id "main_head_search"
Then I see "软件"
Then I see "问答"
Then I see "博客"
Then I see "新闻"
Then I take a screenshot

with-id

搜索输入框

我尝试了把I press view with id "main_head_search" 改成 I press "main_head_search",也能找到该搜索图标。
说明:I press "test/id" 是万能语法,同时支持文本和id定位控件。那我就不用再记住复杂语句I press view with id "main_head_search"了。

no-with-id

输入文本并按回车键搜索

Feature: 搜索包含calabash的博客
...
When I enter "calabash测试" into input field number 1
Then I take a screenshot
When I press the enter button
Then I see "已加载全部"
Then I take a screenshot

calabash-index-enter

输入calabash测试

这里的enter button 就是软键盘上的"搜索"键。

搜索calabash结果

注意: 用index查找控件,是从1开始的,而不是像C/Java数组的元素下标那样从0开始。

为了验证index从1开始,下面再尝试登录

Feature: 登录开源中国

Scenario: 启动应用后,输入账号和密码能登录开源中国
Then I wait for 5 seconds
Then I see "软件版本更新"
Then I see "以后再说"
Then I take a screenshot
When I press "以后再说"
Then I don't see "以后再说"
Then I see "最新资讯"
Then I take a screenshot
Then I press the menu key
Then I see "用户登录"
Then I take a screenshot
When I press "用户登录"
Then I see "记住我的登录信息"
Then I take a screenshot
When I enter "username" into input field number 1
And I enter "123456" into input field number 2
And I press button number 2
Then I see "登录失败用户名或口令错"
Then I take a screenshot

calabash-login

在此输入图片描述

在此输入图片描述

说明:

  1. 登录窗口中,有两个输入框:"账号"和"密码",index分别是1和2
  2. 登录窗口中,有两个button:"记住我的登录信息"和"登录",index分别是1和2,checkbox也是button,奇怪吧?
  3. 尝试I press "登录"定位登录按钮失败

calabash测试集管理

一个Feature下包含多个Scenario

D:\git\oschina\android-app\calabash\features\first.feature 改名为 startup.feature,内容如下:

Feature: 启动开源中国

Scenario: 首次启动应用后,启用左右滑动
When I wait up to 5 seconds to see "软件版本更新"
Then I see "以后再说"
Then I take a screenshot
When I press "以后再说"
Then I don't see "以后再说"
Then I see "最新资讯"
Then I take a screenshot
Then I press the menu key
Then I see "系统设置"
Then I take a screenshot
When I press "系统设置"
Then I see "已关闭左右滑动"
And I see "启动检查更新"
Then I take a screenshot
When I press "已关闭左右滑动"
Then I see "已启用左右滑动"
When I press "启动检查更新"
Then I take a screenshot

Scenario: 第二次启动应用后,往右滑动到"问答"
When I wait up to 5 seconds to see "最新资讯"
When I swipe right
Then I see "问答"
Then I take a screenshot

本Feature有两个Scenario:

  • 第一个在系统设置中启用左右滑动,关闭启动时检查更新
  • 第二个往右滑动到“问答”页

需要说明的是:

  • 每个Feature在运行前都会退出app,卸载app,重装app,启动app
  • 每个Scenario在运行前都会退出app,启动app
  • I see "启动检查更新" 只有在1280x720分辨率的手机上才能看到;854x480的手机上看不到,会运行错误。

一次运行多个Feature文件

按照 http://www.cnblogs.com/puresoul/archive/2011/12/28/2305160.html 的《Cucumber入门之Gherkin》介绍,

一旦我们写好了一个feature文件,我们就可以使用 cucumber命令来运行它。如果cucumber命令后不跟任何东西的话,那么它会执行所有的.feature文件。如果我们只想运行某一个.feature文件,我们可以使用命令cucumber features\feature_name

我现在在目录D:\git\oschina\android-app\calabash\features下有两个feature文件:

D:\git\oschina\android-app\calabash>dir features*.feature
驱动器 D 中的卷是 工作
卷的序列号是 9823-AB19

D:\git\oschina\android-app\calabash\features 的目录

2014/09/14 21:17 775 login.feature
2014/09/15 21:20 932 startup.feature
2 个文件 1,707 字节
0 个目录 131,744,169,984 可用字节

login.feature 和 startup.feature,feature的执行顺序无关紧要,因为每个feature运行时都要重新安装一遍app。

D:\git\oschina\android-app\calabash>calabash-android run ..\bin\oschina-android-app.apk

将执行这两个feature文件。

如果只想执行 startup.feature 文件,要在calabash-android命令后面添加 features\startup.feature

D:\git\oschina\android-app\calabash>calabash-android run ..\bin\oschina-android-app.apk features\startup.feature

中文Win7环境特别说明:
如果feature文件名是中文的,比如:启动.feature,那么在cmd 中 chcp 65001 后,运行命令:

D:\git\oschina\android-app\calabash>calabash-android run ..\bin\oschina-android-app.apk features\启动.feature

将报错:

invalid byte sequence in UTF-8 (ArgumentError)

中文Win7下中文编码统计:

  • 文件名:GBK
  • feature文件内容:UTF-8
  • cmd:首次测试app或换手机后,UTF-8,feature中的中文显示为空白
  • cmd:第二次测试app,GBK,feature中的中文能正确显示

Ubuntu环境下,feature文件名包含中文没有任何问题。

我们看一下calabash-android的命令参数格式:

D:\git\oschina\android-app\calabash>calabash-android
Usage: calabash-android [parameters] [options]
can be one of
help
prints more detailed help information.
gen
generate a features folder structure.
setup
sets up a non-default keystore to use with this test project.
resign
resigns the app with the currently configured keystore.
build
builds the test server that will be used when testing the app.
run
runs Cucumber in the current folder with the enviroment needed.
version
prints the gem version

can be
-v, --verbose
Turns on verbose logging

我猜想其中的[parameters]就是指cucumber参数

扩展calabash预定义指令

从环境变量读取测试数据

有一个现实的需求:
如果有一个oschina测试帐号要在多个Feature中使用,
或者我的calabash测试脚本共享给其他人后,他的oschina测试帐号要换成自己的。
如果直接修改Feature文件中的账号和密码,可能要修改多个地方。
所以,设想是否能扩展calabash预定义指令:

Then /^I enter "([^"]*)" into input field number (\d+)$/ do |text, index|

扩展为支持从环境变量读取输入文本:

Then /^I enter $([^$]*) into input field number (\d+)$/ do |text_ev, index|

从文件 D:\ruby-1.9.3-p545-i386-mingw32\lib\ruby\gems\1.9.1\gems\calabash-android-0.5.1\lib\calabash-android\steps\enter_text_steps.rb 中拷贝:

Then /^I enter "([^"]*)" into input field number (\d+)$/ do |text, index|
enter_text("android.widget.EditText index:#{index.to_i-1}", text)
end

D:\git\oschina\android-app\calabash\features\step_definitions\calabash_steps.rb 中,改动后,如下:

require 'calabash-android/calabash_steps'

Then /^I enter %([^%]*)% into input field number (\d+)$/ do |text_ev, index|
text = ENV[text_ev]
enter_text("android.widget.EditText index:#{index.to_i-1}", text)
end

Then /^I enter $([^$]*) into input field number (\d+)$/ do |text_ev, index|
text = ENV[text_ev]
enter_text("android.widget.EditText index:#{index.to_i-1}", text)
end

这里环境变量支持两种格式:

  • %test_ev% Windows cmd的格式
  • $test_ev Linux Bash的格式

然后运行calabash前,设置环境变量:

D:\git\oschina\android-app\calabash>set td_username_1=username1
D:\git\oschina\android-app\calabash>set td_password_1=123456

上述两条命令也可以放到 testdata.bat 文件中,然后执行testdata.bat:

set td_username_1=username1
set td_password_1=123456

修改 login.feature :

Feature: 登录开源中国

Scenario: 启动应用后,输入错误的账号和密码不能登录
Then I wait for 5 seconds
Then I see "软件版本更新"
Then I see "以后再说"
Then I take a screenshot
When I press "以后再说"
Then I don't see "以后再说"
Then I see "最新资讯"
Then I take a screenshot
Then I press the menu key
Then I see "用户登录"
Then I take a screenshot
When I press "用户登录"
Then I see "记住我的登录信息"
Then I take a screenshot
When I enter %td_username_1% into input field number 1
And I enter $td_password_1 into input field number 2
And I press button number 2
Then I see "登录失败用户名或口令错"
Then I take a screenshot

运行calabash:

D:\git\oschina\android-app\calabash>calabash-android run ..\bin\oschina-android-app.apk features\login.feature

在此输入图片描述

为了支持跨平台测试数据维护,可以把环境变量设置放入ruby脚本 testdata.rb 中:

ENV["td_username_1"]="username1"
ENV["td_password_1"]="123456"

在irb中运行calabash:

D:\git\oschina\android-app\calabash>irb
irb(main):001:0> require './testdata.rb'
=> true
irb(main):002:0> ENV["td_username_1"]
=> "username1"
irb(main):003:0>exec('calabash-android run ..\bin\oschina-android-app.apk features\login.feature')

Ruby设置和读取环境变量真是太方便了,执行系统命令也很方便,不需要到处import库,值得深入掌握。

Linux补充:

Linux下可以把测试数据写入testdata.bashrc 中:

export td_username_1="username1"
export td_password_1="123456"

enter_text_steps.rb 文件位置:

/var/lib/gems/1.9.1/gems/calabash-android-0.5.2/lib/calabash-android/steps/enter_text_steps.rb

ruby控制台下使用query查询app当前页面的控件

参考文档:
https://github.com/calabash/calabash-android/wiki/05-Query-Syntax
http://blog.lesspainful.com/2012/12/18/Android-Query/

按照上述文档很容易查询控件的id, 比如启动开源中国后的首页,查询结果:

D:\git\oschina\android-app\calabash>calabash-android console ..\bin\oschina-android-app.apk
irb(main):001:0> reinstall_apps
5168 KB/s (2498389 bytes in 0.472s)
3800 KB/s (544875 bytes in 0.140s)
nil
irb(main):002:0> start_test_server_in_background
nil

启动后首页弹出升级提示对话框:

在此输入图片描述

irb(main):003:0> query('button')

在此输入图片描述

看出问题没有,中文编码问题又来捣乱了:

"text" => "\u7ACB\u5373\u66F4\u65B0", 的中文是"立即更新",这里只能看的是4个中文字
"text" => "\u4EE5\u540E\u518D\u8BF4", 的中文是"以后再说"

又要说人家Ubuntu了,Ubuntu下query结果的中文能直接显示。

在console下还可以点击按钮,
https://github.com/calabash/calabash-android/blob/master/ruby-gem/lib/calabash-android/steps/press_button_steps.rb 中定义了按button编号点击的指令 :

Then /^I press button number (\d+)$/ do |index|
tap_when_element_exists("android.widget.Button index:#{index.to_i-1}")
end

要选择按钮"以后再说",把 #{index.to_i-1} 代成1, 在console下输入:

tap_when_element_exists("android.widget.Button index:1")

然后按钮"以后再说"被点击,升级提示对话框消失了:

在此输入图片描述

所以,可以放心的在feature文件中加入指令:

Then I press button number 2

下面还希望找到右上角搜索图标的id,在console下输入:

query("*")

总共列出了111个控件,编号从0到110,其中第7个是:

irb(main):008:0> query("*")
[
...
7 {
"id" => "main_head_search",
"enabled" => true,
"contentDescription" => nil,
"class" => "android.widget.ImageButton",
"rect" => {
"center_y" => 90,
"center_x" => 676,
"height" => 80,
"y" => 50,
"width" => 80,
"x" => 636
},
...
]

根据其坐标(x,y) = (636,50),可以确定就是右上角的搜索按钮,按钮的id是main_head_search。

还可以查询本页面的button:

query("imagebutton")

只有1个查询结果,就是搜索按钮:

irb(main):008:0> query("imagebutton")
[
[0] {
"id" => "main_head_search",
"enabled" => true,
"contentDescription" => nil,
"class" => "android.widget.ImageButton",
"rect" => {
"center_y" => 90,
"center_x" => 676,
"height" => 80,
"y" => 50,
"width" => 80,
"x" => 636
},
"tag" => nil,
"description" => "android.widget.ImageButton{42a889a0 VFED..C. ..
...... 636,0-716,80 #7f0b00a3 app:id/main_head_search}"
}
]

接下来可以用两者方式点击搜索按钮,
第一种,对应指令是 Then I press image button number 1

tap_when_element_exists("android.widget.ImageButton index:0")

第二种,对应指令是 Then I press "main_head_search"

tap_when_element_exists("* marked:'main_head_search'")

posted @ 2014-09-01 22:42  超爱fitnesse  阅读(3119)  评论(1)    收藏  举报