XCTest 和 Unit Testing Bundle
開始寫測試前必須先瞭解該平台用來寫測試的套件或框架,
例如 C# 的 MSTest、Java 的 JUnit、JavaScript 的 JsUnit,
當然在 iOS 平台上也有專屬的測試框架 XCTest。
XCTest
XCTest 是 Apple 官方出的測試框架,可以用來建立 Unit Testing、Performance Testing、UI Testing。
Unit Testing Bundle
Unit Testing Bundle 則是 Xcode 內建用來做單元測試的 Target。
初始化
新增 Target > iOS Unit Testing Bundle (在建立專案時其實也可以直接勾選 Include Tests)
命名 Target 名稱 > 完成安裝
通常需要測試的物件都在專案裡,所以
TestAppTests.swift
需要在最上面加上@testable import TestApp
也可以自行新增測試檔案進行分類,建議是一個類別對一個測試檔案,不要把所有類別的測試都寫在同一個檔案
撰寫測試
Setup 和 Teardown
- SetUp:在測試執行前做一些初始化的設定。
- TearDown:測試結束後,在這裡清除資料或設定,確保不會留下任何可能影響後續測試的東西。
目前官方有提供很多種進階用法 Set Up and Tear Down State in Your Tests
例如初始化方式就有分同步或非同步,
或是提供 addTeardownBlock
來定義特定測試的 TearDown。
1 | override func setUp() async throws { |
XCTAssert
用來驗證結果是否如預期,有很多種判斷方式。
1 | let result = true |
執行方式
xcode 的介面上就有三種按法可以跑測試,當然也可以用終端機跑測試。
第一種比較特別,是要設定過 Scheme,並且長按編譯按鈕,然後改成執行測試。
第二或三種比較單純,直接執行單一檔案或是單一測試。
單元測試命名
- 必須以前綴 test 開頭、不帶參數、不返回值,是否用底線由團隊而定
- 最好名稱能夠敘述測試的內容,或是包含預期的結果
1 | test_NumberTool_IsPositive() |
如何把程式寫成可測試
- 乾淨的架構 ( MVC、MVVM、VIPER、Clean 等等架構,架構的細膩程度會直接影響能測試的程度 )
- 職責單一的物件
- 抽離檔案系統 ( UserDefault or File )、資料庫 ( DataBase )、遠端資料 ( Api )
- 抽離的方式最常見的就是使用 Protocol 抽離實作,並且使用依賴注入 ( DI ) 換成假資料
- 或是使用一些實作好 Mock 的套件,例如 MockUserDefaults
常見的測試案例
對 Model 測試
可測試 Model 的建構式或是方法。
1 | struct Cake{ |
1 | func testCakeGetPrice() throws { |
對 API 測試
針對 Server 呼叫 API 進行測試,確認回應物件是否如預期,
因為會依賴真實伺服器,所以不是單元測試而是整合測試。
官方針對非同步測試也有寫文章 - Testing Asynchronous Operations with Expectations
需要建立 XCTestExpectation 並使用 wait,才能確保非同步下測試會正常。
1 | func testDataManagerGetData() { |
對真實環境的抽離並測試
當遇到檔案系統、資料庫、遠端資料,可用 Protocol 抽離實作並依賴注入(DI)
利用假資料來進行完整的商業邏輯的測試。
下面有四步驟:
- 將呼叫遠端資料的邏輯都封裝在一個物件
CakeAPIProvider
,好處是方便抽離 - 建立一個 protocol
CakeProvider
,把要抽離的方法都定義出來 - 真正在管理資料的
CakeManager
只要使用該 protocol 呼叫各種商業邏輯
1 | protocol CakeProvider{ |
- 到時候要進行測試或抽換實作時,只要換
CakeManager
的 provider 即可!
1 | class CakeMockProvider: CakeProvider{ |
測試覆蓋率 (Code Coverage)
測試覆蓋率可以用來看在跑測試的過程中,有多少比例的程式有執行到。
建立方式
編輯 Scheme > Test > 勾選 Code Coverage,
可以選擇特定 target,盡量選擇自己專案就好,不然會包含一些三方依賴。
查看結果
可以從 xcode 的活動紀錄裡看到 Coverage
追求 100% 的測試覆蓋率其實不太容易,
更何況前端很多是 UI 相關的程式碼,也不是那麼容易寫單元測試,
至少確認重要邏輯或是關鍵路徑已經被測試就可以了。
希望這篇文章有幫助到您的開發之路!如果能給我一些按讚支持,我會非常感謝您的鼓勵!祝壞蟲遠離您!