Swift 程式語言

Swift 開發:如何使用 Xcode 7 進行單元測試

Swift 開發:如何使用 Xcode 7 進行單元測試
Swift 開發:如何使用 Xcode 7 進行單元測試
In: Swift 程式語言

甚至情況更差一點,就是找來找去也找不到錯在哪裡。不論你是程式新手或者已經有點經驗的開發者,定期編寫單元測試 (unit testing) 會讓你的程式碼更可靠、安全,當問題出現的時候更能除錯就更容易。

幸運地,Xcode 7 和 Swift 都支援單元測試。雖然使用單元測試不代表錯誤不會出現,但把程式碼分隔為細小的單元,從而逐一檢測每個單元都是正確地執行,此舉有助除錯偵測。

顧名思義,單元測試是逐一為每個單元的程式碼去建立指定的功能測試,以確保每一個單元都能通過。而成功通過的單元程式碼會在旁邊顯示綠色標誌。若果因為某些因素而測試失敗,Xcode 就會直接顯示測試結果為失敗 (failed)。這個標示能讓你找到有問題的程式碼的位置,也方便了追查出錯的原因。

範例專案概要

首先,先我為你準備好的Starting Project下載。這是一個十分簡單的百份比運算 App(舉例:80 x 10%= 8 )。

這個百份比運算器比較簡單。你所需要去看的文檔就只有 ViewController.swift。文檔中,簡潔的程式碼附帶了註釋,讀起來更清晰明白。

文檔中有五個 IBOutlets:一個是屏幕上標題之外的每一個 UIElement;其餘分別是在兩旁的浮動塊 (slider),每邊兩個的 IBActions。每個 IBAction 的名字都準確地說明了操作方法和指令。而當兩個浮動塊,其中一個的值有所改變,其餘的百份比或數字值都會作出調整。

此外,文檔中還可以發現兩個簡單的函數 “updateLabels()” 和 “percentage()”,它們的作用完全是合符開發者的期望:前者是當一個浮動塊作出改動時為標號作出更新,而後者提取兩個浮點值 ,經百份比運算後把結果回傳。

利用模擬器執行一下App。首先,一切看似正常。但當你開始更改數字,你會發現運算出來的答案是錯誤的。要把錯處找出來,我們可以把程式碼區分為不同的單元,並逐一進行測試,以檢查它們是否合符預期地運作。這個動作不能除錯,但絕對有助縮少搜索的範圍。

unit-test-demo-app

在我創建這個專案時,在專案細項選填畫面裡勾選了包含單元測試檔案 (include Unit Tests) 。(若果你想自行加入檔案,選擇 File > New > File > Unit test Case Class under iOS Source)。在這個範例專案,Xcode已經為你準備好這些檔案,並可以在 project navigator 面版中的 “PercentageCalculatorTests” 文件夾裡找到。

xcode-unit-test-option

PercentageCalculatorTests 類別中,PercentageCalculatorTests.swift 為開發者提供了四種測試方法。其中兩個測試方法的檔案是可以被刪除的(測試檔案皆以 test 字為開首,”…Example” 作結尾,便於辨認;以及在欄距有鑽石型圖標作標示)。另外 setUp()tearDown(),這兩個屬於特別調理板方法,每次每個測試方法被執行的之前和之後都會被呼叫出來。

開始動手寫單元測試

現在,是時候讓你寫下第一個單元測試方法。在這個教程中,我們只會針對 ViewController 作出測試,我們會為它在 PercentageCalculatorTests 類別中新增一個實體。

class PercentageCalculatorTests: XCTestCase {
    var vc: ViewController!

    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }

}

PercentageCalculatorTests 類別是 XCTestCase 的子類別,來自 XCTest 框架。而在 XCTestCase 子類別下的每一個實體都是負責測試 你的專案的某一個指定部份,舉例說指定函數。

在 setup 方法中以 vc 為例。在每個測試之前 setUp() 都會被呼叫出來,然後你將會從 ViewController 的每個測試方法裡到得到一個「即時」實體。把 setUp() 方法跟著下列更改:

override func setUp() {
    super.setUp()

    let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
    vc = storyboard.instantiateInitialViewController() as! ViewController
}

現在,記著所有的測試方法名字必須要由關鍵字 test 為開首。否則,Xcode 是不能把它辨認出來。新增一個測試方法 testPercentageCalculator(), 它會為 ViewController 驗證 percentage() 方法是否有用。

func testPercentageCalculator() {
}

在單元測試你會檢查大量程式碼是否正常運作。被測試的大量程式碼通常只有數行,而一般情況下也只會測試單一方法或函數。為單元的程式碼提供輸入值,讓值在程式碼中通過,以及檢查輸出的值是否與我們預期相符,便算是完成了單元測試。

Unit Testing Example

用作比較「我們預期的結果」這部份的是 XCTAssert 函數。而最簡單的 XCTAssert 函數是 XCTAssert(expression: BooleanType)。這個運用了布林表式(好像 5 > 38.90 == 8.90true),若果透過表式測試得出來的評估是 true,XCTAssert 測試就是成功通過。相反,若果評估結果為 false 就為之失敗。

試試看!首先,把下列的程式碼加入至 testPercentageCalculator() 方法。然後移動你的滑鼠,將游標放在方法名稱左側欄的鑽石型圖標上,這時鑽石型圖標會轉變成執行圖標,點擊便開始測試。

func testPercentageCalculator() {
        XCTAssert(true)
}

若果一切順利進行,測試得到成功通過就會在方法旁邊顯示出一個綠色的打勾符號。

unit-test-green-mark

驗證百份比計算器

進入下一步,正式開始。若要測試 percentage() 方法,我們需要使用 vc 去呼叫此方法。給它兩個浮點值,同樣以 50 為例子,並把輸出結果存儲為 p 常數。在這個案例中,p 應該是等於 25(50 x 50% = 25)。使用 XCTAssert(p == 25) 去檢查這個案例並執行測試方法。以下列程式碼取代 testPercentageCalculator() 方法:

func testPercentageCalculator() {
        // Should be 25
        let p = vc.percentage(50, 50)
        XCTAssert(p == 25)
}

成功通過這個測試,意味著 ViewController 裡的 percentage() 函數發揮其功能,那麼我們可以繼續往其他地方偵查錯誤存在的位置,或許可以試一試往 updateLabels() 方法去找。

驗證標記

現在新增一個名為 testLabelValuesShowedProperly() 的測試方法,它可以驗證標記能否把適當的文字顯示出來。同樣地,以 ViewController 呼叫 updateLabels() 方法,以檢查 text 屬性是否每次都能顯示出我們預期的文字。

這裡要注意一下,你需要給 XCTAssert 函數加入一個新的參數:一個以 string 型態的訊息。這是很方便的,因為我們擁有多個值需要透過測試去完成(三個 XCTAssert 呼叫)。假若測試是不成功,這個訊息便會告知我們確實出錯的地方。

func testLabelValuesShowedProperly() {
        vc.updateLabels(Float(80.0), Float(50.0), Float(40.0))

        // The labels should now display 80, 50 and 40
        XCTAssert(vc.numberLabel.text == "80.0", "numberLabel doesn't show the right text")
        XCTAssert(vc.percentageLabel.text == "50.0%", "percentageLabel doesn't show the right text")
        XCTAssert(vc.resultLabel.text == "40.0", "resultLabel doesn't show the right text")
}

當你嘗試執行此方法,你會得到一個錯誤提示為 numberLabelpercentageLabelresultsLabelnil。這怎麼可能?

這是因為我在 storyboard 檔案裡建立這些標記,所以當視圖被加載時它們便會被實例化 (instantiated),但由於單元測試的 loadView() 方法並沒有被觸發,標記因此不能被建立,所以他們是 nil。一個可行的解決辦法是呼叫 vc.loadView(),但 Apple 卻不建議在文檔中這樣做,因為當物件不斷加載再加載或或會導致記憶體洩流 (memory leaks) 的發生。

取而代之,你應該存取 vcview 屬性,它可以觸發所有所需要的方法,而不只是單純是 loadView() 方法。先把 testLabelValuesShowedProperly() 的程式碼作出更新。

func testLabelValuesShowedProperly() {
        let _ = vc.view
        vc.updateLabels(Float(80.0), Float(50.0), Float(40.0))

        // The labels should now display 80, 50 and 40
        XCTAssert(vc.numberLabel.text == "80.0", "numberLabel doesn't show the right text")
        XCTAssert(vc.percentageLabel.text == "50.0%", "percentageLabel doesn't show the right text")
        XCTAssert(vc.resultLabel.text == "40.0", "resultLabel doesn't show the right text")
}

使用底線 ( _ ) 取代成常數名字。這是因為我們實際上不需要也不會用得上它。基本上它只是告知編譯程式「只是假裝存取視圖及觸發方法」。

執行測試。(如果你想在我們的測試類別裡執行所有的測試,你可以勾選 “class PercentageCalculatorTests” 的小方格)

unit-test-demo-fail

錯誤處理

如你所見測試是失敗的!這個方法裡輸入的詳細錯誤訊息,能使我們快速地辨認出錯誤的潛在原因。這個測試是告訴我們 resultsLabel 不能顯示出正確的文字。接下來,前往 ViewController 並看看在哪裡設定這些標記的文字值。仔細研究 ViewController.swiftupdateLabels() 的程式碼,我們發現了錯誤原因:

self.resultLabel.text = "\(rV + 10)"

應該是:

self.resultLabel.text = "\(rV)"

再次編譯與執行測試。問題得到解決,一切都得到順利進行。

結語

在這個教程,你嘗試到在 Xcode 使用單元測試,並了解它是如何協助你尋找隱藏在程式碼中的錯誤。除了避免錯誤發生,單元測試還可以用作效能測試 (Performance Testing) 和 異步測試 (Asynchronous Testing)。還有,或許你會有興趣了解一下 UI 自動化測試 (UI Testing),透過錄製的方式記錄 App 的實際操作,並讓開發者檢視其效能表現。關於 UI 自動化測試,可以瀏覽 WWDC 視頻

本教程的完整專案範例可以在 GitHub 下載

如果你對單完測試或本教程有任何疑問或困難,歡迎留言查詢。

譯者簡介:小秘,業餘博客,翻譯新手,最愛睡覺,喜歡旅遊。

原文Unit Testing in Xcode 7 with Swift

作者
Maxime Defauw
Maxime Defauw 擁有豐富的程式設計經驗,以往曾在App Store及Google Play Store 發佈多個個人開發的Apps。現年16歲的Max居於比利時,精通Objective-C, C, C#及Swift等多種電腦程式語言。今年的6月,Max獲Apple的贊助出席於在三藩巿舉行的WWDC15!在埋首於程式設計以外的時間,Max還喜歡曲棍球和高爾夫球等運動。
評論
更多來自 AppCoda 中文版
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。