如何使用UIAutomation進行iOS 自動化測試(Part I)
寫在前面
研究iOS的自動化測試也有些日子了,剛開始的時候,一直苦於找不到什麼好的資料,只能從Apple的官網查閱相關的API文件,只可惜,Apple對開發者來說實在是不怎麼友好,文件寫得相當的粗略,對於初學者來說有一定的難度。
本來是打算自己動手寫一篇關於iOS的UI自動化測試的入門級別的介紹性文件的,但想起來後面在具體解決一些問題的時候,收藏一篇很好的Blog,很全面地介紹瞭如何使用UIAutomation的JavaScript Libraries做iOS程式的自動化測試。如果作者早點看到這篇文章,應該要少走一些彎路,這裡沒有創意性的它他翻譯成中文,希望對你們有一些幫助。
翻譯正文:
快速入門
自動化測試程式碼可以“在你的睡著的時候”很好地幫你測試你的應用程式。它可以讓你能夠快速地跟蹤你程式中的迴歸和效能方面的問題,這樣你就不用擔心你新增的功能會影響到你之前已經完成開發的程式了。
隨著iOS4.0的釋出,蘋果公司同時釋出了一個名為UIAutomation的測試框架,它可以用來在真實裝置和iPhone模擬器上執行自動化測試。但官方關於UIAutomation的文件相當的有限,在網路上也沒有太多的資源可以查詢的。本文將向你展示你如何將UIAutomation整合到你的工作流程當中去。
除此之外,包括在Xcode中的OCUnit測試框架也可以用來為你的應用程式編寫單元測試。
1. 第一個UIAutomation測試指令碼
- 使用iOS 模擬器
- 使用iOS裝置
2. 處理UIAElement和元素可訪問性(Accessibility)
- UIAElement層次結構
- 模擬使用者操作
3. 經驗分享(讓你的生活變得更簡單)
- 類庫Tune-up介紹
- 匯入外部指令碼
- 使用強大的命令列
- 使用錄製互動功能
- 當遇到問題時,加上“UIATarget.delay(1);”
4. 高階互動
- 處理非預期和預期的提示框(alerts)
- 多工
- 螢幕方向
5. 總結
- 有用的連結
- 一個視訊
1. 你的第一個UIAutomation測試指令碼
UIAutomation的功能測試程式碼是用Javascript編寫的。UIAutomation和Accessibility有著直接的關係,你將用到通過標籤和值的訪問性來獲得UI元素,同時完成相應的互動操作。
下面讓我們來編寫我們的第一段測試程式碼。
使用iOS模擬器
1. 下載示例應用程式TestAutomation.xcodeproj,並開啟它。這個專案是一個很簡單的包含2個tab的tabbar應用程式。
2. 確保選中如下圖所示的“TestAutomation > iPhone 5.0 Simulator”模式(或許你已經切換成5.1了,因此它可能是iPhone5.1模擬器)。
3. 啟動Instruments(Product > Profile),或者通過⌘I。
4. 選擇左邊的iOS Simulator,然後再選擇Automation模板,然後點選“Profile”。
5. Instruments就已經啟動好後,然後直接開始錄製了。這裡先停止錄製,(紅包按鈕或者⌘R)。
6. 在左邊的Scripts視窗,點選“Add > Create”建立新的指令碼。
7. 在指令碼編輯器裡,輸入下面的程式碼
var target = UIATarget.localTarget();
var app = target.frontMostApp();
var window = app.mainWindow();
target.logElementTree();
8. 重新執行這段指令碼⌘R(不需要儲存)。指令碼跑起來後,你可以在日誌打完後停止它。
贊一個!我們就這樣完成了我們的第一個UIAutomation測試用例。
使用iOS裝置
你除了將你的測試用例執行模擬器上,也可以將它執行在一個真實的裝置上。不過,自動化測試用例只能執行在支援多工的:iPhone 3GS,iPad,iOS > 4.0等裝置上。遺憾的是不管iPhone 3G的系統版本是什麼,都不支援。
下面是如何操作:
1. 通過USB介面連線上你的iPhone。
2. 選擇 “TestAutomation > iOS Device”模式。
3. 確保Developper profile設定成Release模式(而不是Ad-Hoc Distribution profile)。預設情況下,profiling是設定成Release模式的(因為沒有必要將profile設定成Debug模式)。
5. 後面的步驟請參考前面模擬器部分。
2. 處理UIAElement和元素可訪問性(Accessibility)
UIAElement層次結構
Accessibility和UIAutomation有密切的聯絡:如果一個控制元件的Accessibility是可以被訪問的,你就可以設定和讀取它的值,作相關的操作,而當一個控制元件的Accessibility不可見時,你就沒有辦法通過automation訪問它。
你可以通過Interface Builder,或者通過在程式裡設定isAccessibilityElement屬性的方式來設定一個控制元件的Accessibility或者可被自動化。當你設定container view(即:一個檢視包含其它的UIKit元素)的accessibility時,你必須注意。你設定了整個View的accessibility將會“隱藏”它的子檢視的accessibility,例如:在示例專案中,你不能將outlet檢視設定成可訪問的,否則它所有的子控制元件將都不可以訪問了。在任何時候,logElementTree都是你忠實的朋友:它將當前介面的所有可被訪問的元素都列印在日誌裡。
每一個可以被訪問的UIKit控制元件都可以用一個Javascript物件來描述,它就是一個UIAElement。UIAElement有幾個屬性:name, value, elements, parent。你的主視窗包含很多的控制元件,它們是以UIKit層次的方式定義的,這些UIKit層次結構對應的是UIAElement的層次樹。例如:前面的測試程式碼中,通過呼叫logElementTree,我們可以得到如下面所示的樹結構:
+- UIATarget: name:iPhone Simulator rect:{{0,0},{320,480}}
| +- UIAApplication: name:TestAutomation rect:{{0,20},{320,460}}
| | +- UIAWindow: rect:{{0,0},{320,480}}
| | | +- UIAStaticText: name:First View value:First View rect:{{54,52},{212,43}}
| | | +- UIATextField: name:User Text value:Tap Some Text Here ! rect:{{20,179},{280,31}}
| | | +- UIAStaticText: name:The text is: value:The text is: rect:{{20,231},{112,21}}
| | | +- UIAStaticText: value: rect:{{145,231},{155,21}}
| | | +- UIATabBar: rect:{{0,431},{320,49}}
| | | | +- UIAImage: rect:{{0,431},{320,49}}
| | | | +- UIAButton: name:First value:1 rect:{{2,432},{156,48}}
| | | | +- UIAButton: name:Second rect:{{162,432},{156,48}}
你可以通過下面的程式碼來訪問文字框:
var textField =
UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0];
你可以選擇通過從0開始的索引或者這個元素的名稱來訪問這個元素,例如:你也可以通過下面的程式碼來訪問文字控制元件。
var textField =
UIATarget.localTarget().frontMostApp().mainWindow().textFields()["User Text"];
後一種方式更加清晰明瞭,應該多使用。你可以通過Interface Builder設定UIAElement的name屬性,
或者通過編寫程式碼的方式:
myTextField.accessibilityEnabled = YES;
myTextField.accessibilityLabel = @"User Text";
你現在可以看到,通過accessibility屬性可以被UIAutomation用來找到不同的控制元件。這非常的清晰,因為,第一,你只要學習一個測試框架;第二,通過編寫自動化測試程式碼,你同時還可以保證你的程式是可以被訪問的。因此,每一個UIAElement物件的子控制元件可以通過下面的方法進行訪問:
buttons(), images(), scrollViews(),textFields(), webViews(), segmentedControls(), sliders(), staticTexts(), switches(), tabBar(),tableViews(), textViews(), toolbar(), toolbars() 等等……
你可以通過如下程式碼在tabbar上訪問第一個tab:
var tabBar = UIATarget.localTarget().frontMostApp().tabBar();
var tabButton = tabBar.buttons()["First"];
UIAElement結構層次非常的重要,你以後會常常用到它。而且你還要記住,你可以在隨時通過呼叫UIAAplication的logElementTree來獲得它的結構。
UIATarget.localTarget().frontMostApp().logElementTree();
在模擬器上,你還可以啟用Accessibility 的檢測器。啟動模擬器,找到“Settings > General > Accessibility > Accessibility Inspector”,然後將它設為“開啟”狀態。
這個彩色的小框框就是Accessibility 檢測器了。當它收起來的時候,Accessibility就被關閉了,當它展開的時候,Accessibility就是開啟的。你只要點選上面的箭頭按鈕就可以啟用或者遮蔽Accessibility。現在,開啟我們的示例程式,啟用檢測器。
然後,點選文字框,檢查UIAElement的name和value屬性(其實就是accessibilityLabel和accessibilityValue對應的NSObject型別的值)。這個檢測器可以幫助你除錯和編寫你的測試程式碼。
模擬使用者操作
讓我們更進一步,模擬一些使用者的互動操作。你可以簡單地呼叫按鈕的tap()來作一個點選操作:
var tabBar = UIATarget.localTarget().frontMostApp().tabBar();
var tabButton = tabBar.buttons()["First"];
// Tap the tab bar !
tabButton.tap();
你還可以呼叫UIAButtons的doubleTap(), twoFingerTap()。如果你不想操作具體的某個元素,你也可以直接根據螢幕上指定的座標點進行操作,你可以這麼用:
- 點選:
UIATarget.localTarget().tap({x:100, y:200});
UIATarget.localTarget().doubleTap({x:100, y:200});
UIATarget.localTarget().twoFingerTap({x:100, y:200});
- 縮放:
UIATarget.localTarget().pinchOpenFromToForDuration({x:20, y:200},{x:300, y:200},2);
UIATarget.localTarget().pinchCloseFromToForDuration({x:20, y:200}, {x:300, y:200},2);
- 拖拽與划動:
UIATarget.localTarget().dragFromToForDuration({x:160, y:200},{x:160,y:400},1);
UIATarget.localTarget().flickFromTo({x:160, y:200},{x:160, y:400});
注意,當你指定操作的時間間隔的時候,它是有特定的範圍的,即:拖拽操作的時間間隔必須大於或者等於0.5秒,小於60秒。
現在,讓我們來練習一下:
- 停止Instruments (⌘R)
- 在Scripts窗口裡, 移除當前的指令碼
- 點選“Add > Import”然後選擇TestAutomation/TestUI/Test-1.js(將下面的程式碼儲存到這個路徑)
- 點選錄製按鈕 (⌘R) 然後看看將會發生什麼…
下面是Test-1.js程式碼:
var testName = "Test 1";
var target = UIATarget.localTarget();
var app = target.frontMostApp();
var window = app.mainWindow();
UIALogger.logStart( testName );
app.logElementTree();
//-- select the elements
UIALogger.logMessage( "Select the first tab" );
var tabBar = app.tabBar();
var selectedTabName = tabBar.selectedButton().name();
if (selectedTabName != "First") {
tabBar.buttons()["First"].tap();
}
//-- tap on the text fiels
UIALogger.logMessage( "Tap on the text field now" );
var recipeName = "Unusually Long Name for a Recipe";
window.textFields()[0].setValue(recipeName);
target.delay( 2 );
//-- tap on the text fiels
UIALogger.logMessage( "Dismiss the keyboard" );
app.logElementTree();
app.keyboard().buttons()["return"].tap();
var textValue = window.staticTexts()["RecipeName"].value();
if (textValue === recipeName){
UIALogger.logPass( testName );
}
else{
UIALogger.logFail( testName );
}
這段指令碼先啟動待測程式,然後,如果第一個tab沒有被選的話就切換到第一個tab,並將上面的文字框的值設成“Unusually Long Name for a Recipe”,接著收起虛擬鍵盤。這裡有一些新的方法值得注意的:UIATarget的delay(Number timeInterval) 方法允許你在兩個操作之間做一些等待,UIALogger的logMessage( String message) 方法用來將你想列印的資訊輸出到日誌上去,UIALogger的logPass(String message)方法指明你的測試指令碼已經成功的完成測試了。
你還知道了如何訪問鍵盤上的按鈕,然後作點選操作:
app.keyboard().buttons()["return"].tap();
由於時間有限且原文太長,先只能翻譯到這裡,我會盡快的將剩下的部分翻譯補上。另外,時間倉促,如有翻譯得不準確的地方,也敬請擔待。謝謝。
本文由知平軟體的Dawson Liu翻譯,轉載請註明出處。
知平軟體致力於移動平臺自動化測試技術的研究,我們希望通過向社群貢獻知識和開源專案,來促進行業和自身的發展。
var isLogined = false; var cb_blogId = 123488; var cb_entryId = 2631949; var cb_blogApp = currentBlogApp; var cb_blogUserGuid = "4c20a564-9fd4-e111-aa3f-842b2b196315"; var cb_entryCreatedDate = '2012/8/10 15:47:00'; var enableGoogleAd = true; var googletag = googletag || {}; googletag.cmd = googletag.cmd || [];
原文地址:http://www.cnblogs.com/vowei/archive/2012/08/10/2631949.html 本文地址:藍色夢想網:http://www.58os.com/BBS/TechBSS/Article-3509.html TAG標籤: