使用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中應該如下行:

<uses-permission android:name="android.permission.INTERNET" />

在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    <DIR>          .
2014/09/01  20:26    <DIR>          ..
2014/09/01  20:21               783 .classpath
2014/09/01  20:21    <DIR>          .git
2014/09/01  20:21                64 .gitignore
2014/09/01  20:21               822 .project
2014/09/01  20:21    <DIR>          .settings
2014/09/01  20:21            10,829 AndroidManifest.xml
2014/09/01  20:21    <DIR>          assets
2014/09/01  20:42    <DIR>          bin
2014/09/01  20:26    <DIR>          gen
2014/09/01  20:21    <DIR>          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    <DIR>          res
2014/09/01  20:21    <DIR>          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    <DIR>          .
2014/09/01  21:54    <DIR>          ..
2014/09/01  21:54    <DIR>          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 <command-name> [parameters] [options]
  <command-name> 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 <apk>
      resigns the app with the currently configured keystore.
    build <apk>
      builds the test server that will be used when testing the app.
    run <apk>
      runs Cucumber in the current folder with the enviroment needed.
    version
      prints the gem version

  <options> 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'")


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM