含義:編程語言中的單元測試是為了確保編寫的代碼按預(yù)期工作。
給定一個特定的輸入,希望代碼帶有一個特定的輸出。通過測試代碼,能夠給當前的重構(gòu)和發(fā)布建立信心,因為將能夠確保代碼在成功運行的測試套件后按預(yù)期工作。
一、單元測試簡介
單元測試是運行和驗證一段代碼(稱為“單元”)以確保其按預(yù)期運行并符合其設(shè)計的自動化測試。
例如,寫一個字符串擴展方法將第一個字母大寫:
extension String {
func uppercasedFirst() -> String {
let firstCharacter = prefix(1).capitalized
let remainingCharacters = dropFirst().lowercased()
return firstCharacter + remainingCharacters
}
}
我們要確保 uppercasedFirst()方法按預(yù)期工作。如果我們給它一個輸入 antoine,我們期望它輸出 Antoine。我們可以使用XCTAssertEqual 方法為此方法編寫單元測試:
final class StringExtensionsTests: XCTestCase {
func testUppercaseFirst() {
let input = "antoine"
let expectedOutput = "Antoine"
XCTAssertEqual(input.uppercasedFirst(), expectedOutput, "The String is not correctly capitalized.")
}
}
如果我們的方法不再按預(yù)期工作(比如上面的擴展代碼不小心被修改了),Xcode 將使用我們提供的描述顯示失?。?br>
二、項目中添加單元測試
-
創(chuàng)建項目時勾選單元測試
-
已有項目添加測試target
左下角添加target,搜索test,選擇Unit Test Bundle -
項目中就會出現(xiàn)單元測試的文件夾
三、在 Swift 中編寫單元測試
有多種方法可以測試相同的結(jié)果,但是當測試失敗時它并不總是給出相同的反饋。以下提示可幫助您編寫測試,通過從詳細的失敗消息中獲益,幫助您更快地解決失敗的測試。
1.命名測試用例和方法
描述你的單元測試是很重要的,這樣你就會明白測試試圖驗證什么。如果你不能想出一個簡短的名字,那你可能測試了太多東西。一個好名字還可以幫助您更快地解決失敗的測試。
要快速找到特定類的測試用例,建議使用相同的命名并結(jié)合 “test”。就像上面的例子一樣,我們根據(jù)我們正在測試一組字符串擴展的事實命名了 StringExtensionTests。如果您正在測試ContentViewModel 實例,另一個示例可能是 ContentViewModelTests。
2.不要所有測試都使用 XCTAssert
許多場景都可以使用 XCTAssert,但當測試失敗時會導(dǎo)致不同的結(jié)果。以下代碼行都測試了完全相同的結(jié)果:
func testEmptyListOfUsers() {
let viewModel = UsersViewModel(users: ["Ed", "Edd", "Eddy"])
XCTAssert(viewModel.users.count == 0)
XCTAssertTrue(viewModel.users.count == 0)
XCTAssertEqual(viewModel.users.count, 0)
}
正如你所看到的,該方法使用了一個描述性的名字,告訴人們要測試一個空的用戶列表。然而,我們定義的視圖模型不是空的,因此,所有的斷言都失敗了。
結(jié)果顯示了為什么必須對驗證類型使用正確的斷言。 XCTAssertEqual 方法為我們提供了有關(guān)斷言失敗原因的更多上下文。這顯示在紅色錯誤和控制臺日志中,可幫助您快速識別失敗的測試。
3.Setup and Teardown
多個測試方法中使用的參數(shù)可以定義為測試用例類中的屬性。您可以使用 setUp() 方法為每個測試方法設(shè)置初始狀態(tài),并使用 tearDown() 方法進行清理。有多種設(shè)置和拆卸方法的變體供您選擇,例如支持并發(fā)的變體或拋出變體,如果設(shè)置失敗,您可以在其中提前使測試失敗。
一個可以生成用戶默認實例以用于單元測試的示例:
struct SearchQueryCache {
var userDefaults: UserDefaults = .standard
func storeQuery(_ query: String) {
/// ...
}
}
final class SearchQueryCacheTests: XCTestCase {
private var userDefaults: UserDefaults!
private var userDefaultsSuiteName: String!
override func setUpWithError() throws {
try super.setUpWithError()
userDefaultsSuiteName = UUID().uuidString
userDefaults = UserDefaults(suiteName: userDefaultsSuiteName)
}
override func tearDownWithError() throws {
try super.tearDownWithError()
userDefaults.removeSuite(named: userDefaultsSuiteName)
userDefaults = nil
}
func testSearchQueryStoring() {
/// 使用生成的用戶默認值作為輸入。
let cache = SearchQueryCache(userDefaults: userDefaults)
/// ... write the test
}
}
這樣做可以確保您不會操縱在模擬器上測試期間使用的標準用戶默認值。其次,您將確保在測試開始時處于干凈狀態(tài)。我們使用了拆卸方法來刪除用戶默認套件并進行相應(yīng)的清理。
4.拋出方法
和編寫應(yīng)用程序代碼時一樣,您也可以定義一個可拋出測試的方法。這允許您在測試中的方法拋出錯誤時使測試失敗。例如,在測試 JSON 響應(yīng)的解碼時:
func testDecoding() throws {
/// 當數(shù)據(jù)初始值設(shè)定項拋出錯誤時,測試將失敗。
let jsonData = try Data(contentsOf: URL(string: "user.json")!)
/// `XCTAssertNoThrow` 可用于獲取有關(guān)拋出的額外上下文
XCTAssertNoThrow(try JSONDecoder().decode(User.self, from: jsonData))
}
當在任何進一步的測試執(zhí)行中不需要 throwing 方法的結(jié)果時,可以使用 XCTAssertNoThrow 方法。您應(yīng)該使用 XCTAssertThrowsError 方法來匹配預(yù)期的錯誤類型。例如,您可以為證書密鑰驗證程序編寫測試:
struct LicenseValidator {
enum Error: Swift.Error {
case emptyLicenseKey
}
func validate(licenseKey: String) throws {
guard !licenseKey.isEmpty else {
throw Error.emptyLicenseKey
}
}
}
class LicenseValidatorTests: XCTestCase {
let validator = LicenseValidator()
func testThrowingEmptyLicenseKeyError() {
XCTAssertThrowsError(try validator.validate(licenseKey: ""), "An empty license key error should be thrown") { error in
/// 我們確保預(yù)期的錯誤被拋出。
XCTAssertEqual(error as? LicenseValidator.Error, .emptyLicenseKey)
}
}
func testNotThrowingLicenseErrorForNonEmptyKey() {
XCTAssertNoThrow(try validator.validate(licenseKey: "XXXX-XXXX-XXXX-XXXX"), "Non-empty license key should pass")
}
}
5.可選值解包
XCTUnwrap 方法最適合用于拋出測試,因為它是一個拋出斷言:
func testFirstNameNotEmpty() throws {
let viewModel = UsersViewModel(users: [“Antoine”, “Maaike”, “Jaap”])
let firstName = try XCTUnwrap(viewModel.users.first)
XCTAssertFalse(firstName.isEmpty)
}
XCTUnwrap 斷言可選變量的值不為 nil,如果斷言成功則返回它的值。它會阻止您編寫 XCTAssertNotNil 并結(jié)合解包或處理其余測試代碼的條件鏈接。
四、在 Xcode 中運行單元測試
編寫測試后,就該運行它們了。通過以下提示,這將變得更有效率。
1.使用測試三角形
您可以使用前導(dǎo)三角形運行單個測試或一組測試:
根據(jù)最新的測試運行結(jié)果,同一方塊顯示紅色或綠色。
2.重新運行最新的測試
使用以下命令重新運行上次運行測試:
? Control + ? Option + ? Command + G.
上面的快捷方式可能是我最常用的快捷方式之一,因為它可以幫助我在對失敗測試實施修復(fù)后快速重新運行測試。
3. 運行測試組合
使用 CTRL 或 SHIFT 選擇要運行的測試,右鍵單擊并選擇“Run X Test Methods”。
4.在測試導(dǎo)航器中應(yīng)用過濾器
- 使用搜索字段根據(jù)名稱搜索特定測試
- 僅顯示當前所選方案的測試。如果您有多個測試方案,這將很有用。
- 只顯示失敗的測試。這將幫助您快速找到失敗的測試
五、問題統(tǒng)計
1. 運行單元測試后代碼簽名失敗
應(yīng)用程序已經(jīng)打開了自動簽名,所以我認為當測試目標也沒有打開自動簽名時,Xcode 中出現(xiàn)了問題。代碼簽名需要一致。文章來源:http://www.zghlxwxcb.cn/news/detail-515170.html
2. 在單元測試中引用Framework
頭部添加包名稱@testable import (name)
文章來源地址http://www.zghlxwxcb.cn/news/detail-515170.html
到了這里,關(guān)于Swift 單元測試入門的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!