自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Swift 單元測(cè)試入門,你學(xué)會(huì)了嗎?

開發(fā) 前端
有多種方法可以測(cè)試相同的結(jié)果,但是當(dāng)測(cè)試失敗時(shí)它并不總是給出相同的反饋。以下提示可幫助您編寫測(cè)試,通過從詳細(xì)的失敗消息中獲益,幫助您更快地解決失敗的測(cè)試。

前言

編程語言中的單元測(cè)試是為了確保編寫的代碼按預(yù)期工作。給定一個(gè)特定的輸入,您希望代碼帶有一個(gè)特定的輸出。通過測(cè)試您的代碼,能夠給您當(dāng)前的重構(gòu)和發(fā)布建立信心,因?yàn)槟鷮⒛軌虼_保代碼在成功運(yùn)行您的測(cè)試套件后按預(yù)期工作。

許多開發(fā)人員不編寫單元測(cè)試,因?yàn)樗麄冋J(rèn)為這會(huì)花費(fèi)太多時(shí)間,有可能錯(cuò)過最后期限。在我看來,單元測(cè)試會(huì)讓你在最后期限前完成更多工作,因?yàn)槟銜?huì)花更少的時(shí)間解決錯(cuò)誤或?yàn)殛P(guān)鍵問題打補(bǔ)丁。

這篇文章內(nèi)不會(huì)涵蓋 內(nèi)存泄漏測(cè)試 或 為共享擴(kuò)展編寫 UI 測(cè)試,而是主要關(guān)注編寫更好的單元測(cè)試。我還將分享幫助我開發(fā)更好、更穩(wěn)定的應(yīng)用程序的最佳實(shí)踐。

什么是單元測(cè)試

單元測(cè)試是運(yùn)行和驗(yàn)證一段代碼(稱為“單元”)以確保其按預(yù)期運(yùn)行并符合其設(shè)計(jì)的自動(dòng)化測(cè)試。

單元測(cè)試在 Xcode 中有它們的 target,并使用 XCTest 框架編寫。XCTestCase 的子類包含要運(yùn)行的測(cè)試方法,其中只有以 "test" 開頭的方法才會(huì)被 Xcode 解析并允許運(yùn)行。

例如,假設(shè)有一個(gè)字符串?dāng)U展方法將第一個(gè)字母大寫:

extension String {
func uppercasedFirst() -> String {
let firstCharacter = prefix(1).capitalized
let remainingCharacters = dropFirst().lowercased()
return firstCharacter + remainingCharacters
}
}

我們要確保 uppercasedFirst() 方法按預(yù)期工作。如果我們給它一個(gè)輸入 antoine,我們期望它輸出 Antoine。我們可以使用 XCTAssertEqual 方法為此方法編寫單元測(cè)試:

final class StringExtensionsTests: XCTestCase {
func testUppercaseFirst() {
let input = "antoine"
let expectedOutput = "Antoine"
XCTAssertEqual(input.uppercasedFirst(), expectedOutput, "The String is not correctly capitalized.")
}
}

如果我們的方法不再按預(yù)期工作(比如上面的擴(kuò)展代碼不小心被修改了),Xcode 將使用我們提供的描述顯示失敗:

圖片

在 Swift 中編寫單元測(cè)試

有多種方法可以測(cè)試相同的結(jié)果,但是當(dāng)測(cè)試失敗時(shí)它并不總是給出相同的反饋。以下提示可幫助您編寫測(cè)試,通過從詳細(xì)的失敗消息中獲益,幫助您更快地解決失敗的測(cè)試。

命名測(cè)試用例和方法

描述你的單元測(cè)試是很重要的,這樣你就會(huì)明白測(cè)試試圖驗(yàn)證什么。如果你不能想出一個(gè)簡(jiǎn)短的名字,那你可能測(cè)試了太多東西。一個(gè)好名字還可以幫助您更快地解決失敗的測(cè)試。

要快速找到特定類的測(cè)試用例,建議使用相同的命名并結(jié)合 “test”。就像上面的例子一樣,我們根據(jù)我們正在測(cè)試一組字符串?dāng)U展的事實(shí)命名了 StringExtensionTests。如果您正在測(cè)試ContentViewModel 實(shí)例,另一個(gè)示例可能是 ContentViewModelTests。

不要所有測(cè)試都使用 XCTAssert

許多場(chǎng)景都可以使用 XCTAssert,但當(dāng)測(cè)試失敗時(shí)會(huì)導(dǎo)致不同的結(jié)果。以下代碼行都測(cè)試了完全相同的結(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)
}

正如你所看到的,該方法使用了一個(gè)描述性的名字,告訴人們要測(cè)試一個(gè)空的用戶列表。然而,我們定義的視圖模型不是空的,因此,所有的斷言都失敗了。

圖片

結(jié)果顯示了為什么必須對(duì)驗(yàn)證類型使用正確的斷言。XCTAssertEqual 方法為我們提供了有關(guān)斷言失敗原因的更多上下文。這顯示在紅色錯(cuò)誤和控制臺(tái)日志中,可幫助您快速識(shí)別失敗的測(cè)試。

Setup and Teardown

多個(gè)測(cè)試方法中使用的參數(shù)可以定義為測(cè)試用例類中的屬性。您可以使用 setUp() 方法為每個(gè)測(cè)試方法設(shè)置初始狀態(tài),并使用 tearDown() 方法進(jìn)行清理。有多種設(shè)置和拆卸方法的變體供您選擇,例如支持并發(fā)的變體或拋出變體,如果設(shè)置失敗,您可以在其中提前使測(cè)試失敗。

一個(gè)可以生成用戶默認(rèn)實(shí)例以用于單元測(cè)試的示例:

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() {
/// 使用生成的用戶默認(rèn)值作為輸入。
let cache = SearchQueryCache(userDefaults: userDefaults)

/// ... write the test
}
}

這樣做可以確保您不會(huì)操縱在模擬器上測(cè)試期間使用的標(biāo)準(zhǔn)用戶默認(rèn)值。其次,您將確保在測(cè)試開始時(shí)處于干凈狀態(tài)。我們使用了拆卸方法來刪除用戶默認(rèn)套件并進(jìn)行相應(yīng)的清理。

拋出方法

和編寫應(yīng)用程序代碼時(shí)一樣,您也可以定義一個(gè)可拋出測(cè)試的方法。這允許您在測(cè)試中的方法拋出錯(cuò)誤時(shí)使測(cè)試失敗。例如,在測(cè)試 JSON 響應(yīng)的解碼時(shí):

func testDecoding() throws {
/// 當(dāng)數(shù)據(jù)初始值設(shè)定項(xiàng)拋出錯(cuò)誤時(shí),測(cè)試將失敗。
let jsonData = try Data(contentsOf: URL(string: "user.json")!)

/// `XCTAssertNoThrow` 可用于獲取有關(guān)拋出的額外上下文
XCTAssertNoThrow(try JSONDecoder().decode(User.self, from: jsonData))
}

當(dāng)在任何進(jìn)一步的測(cè)試執(zhí)行中不需要 throwing 方法的結(jié)果時(shí),可以使用 XCTAssertNoThrow 方法。您應(yīng)該使用 XCTAssertThrowsError 方法來匹配預(yù)期的錯(cuò)誤類型。例如,您可以為證書密鑰驗(yàn)證程序編寫測(cè)試:

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ù)期的錯(cuò)誤被拋出。
XCTAssertEqual(error as? LicenseValidator.Error, .emptyLicenseKey)
}
}

func testNotThrowingLicenseErrorForNonEmptyKey() {
XCTAssertNoThrow(try validator.validate(licenseKey: "XXXX-XXXX-XXXX-XXXX"), "Non-empty license key should pass")
}
}

可選值解包

XCTUnwrap 方法最適合用于拋出測(cè)試,因?yàn)樗且粋€(gè)拋出斷言:

func testFirstNameNotEmpty() throws {
let viewModel = UsersViewModel(users: ["Antoine", "Maaike", "Jaap"])

let firstName = try XCTUnwrap(viewModel.users.first)
XCTAssertFalse(firstName.isEmpty)
}

XCTUnwrap 斷言可選變量的值不為 nil,如果斷言成功則返回它的值。它會(huì)阻止您編寫 XCTAssertNotNil 并結(jié)合解包或處理其余測(cè)試代碼的條件鏈接。

在 Xcode 中運(yùn)行單元測(cè)試

編寫測(cè)試后,就該運(yùn)行它們了。通過以下提示,這將變得更有效率。

使用測(cè)試三角形

您可以使用前導(dǎo)三角形運(yùn)行單個(gè)測(cè)試或一組測(cè)試:

圖片

根據(jù)最新的測(cè)試運(yùn)行結(jié)果,同一方塊顯示紅色或綠色。

重新運(yùn)行最新的測(cè)試

使用以下命令重新運(yùn)行上次運(yùn)行測(cè)試:

? Control + ? Option + ? Command + G.

上面的快捷方式可能是我最常用的快捷方式之一,因?yàn)樗梢詭椭以趯?duì)失敗測(cè)試實(shí)施修復(fù)后快速重新運(yùn)行測(cè)試。

運(yùn)行測(cè)試組合

使用 CTRL 或 SHIFT 選擇要運(yùn)行的測(cè)試,右鍵單擊并選擇“Run X Test Methods”。

圖片

在測(cè)試導(dǎo)航器中應(yīng)用過濾器

測(cè)試導(dǎo)航器底部的過濾欄允許您縮小測(cè)試概覽范圍。

圖片

  • 使用搜索字段根據(jù)名稱搜索特定測(cè)試
  • 僅顯示當(dāng)前所選方案的測(cè)試。如果您有多個(gè)測(cè)試方案,這將很有用。
  • 只顯示失敗的測(cè)試。這將幫助您快速找到失敗的測(cè)試。

在側(cè)邊欄中啟用覆蓋

圖片

測(cè)試迭代計(jì)數(shù)向您顯示在上次運(yùn)行測(cè)試期間是否命中了特定代碼段。

圖片

它顯示了迭代次數(shù)(在上面的示例中為 3),一段代碼在到達(dá)時(shí)變?yōu)榫G色。當(dāng)一段代碼是紅色時(shí),這意味著它在上次運(yùn)行的測(cè)試中沒有被覆蓋。

編寫單元測(cè)試時(shí)的心態(tài)

你的心態(tài)是編寫高質(zhì)量單元測(cè)試的一個(gè)很好的起點(diǎn)。通過一些基本原則,您可以確保工作效率、保持專注并編寫您的應(yīng)用程序最需要的測(cè)試。

您的測(cè)試代碼與您的應(yīng)用程序代碼一樣重要

在深入探討實(shí)用技巧之后,我想介紹一種必要的心態(tài)。就像編寫應(yīng)用程序代碼一樣,您應(yīng)該盡最大努力編寫高質(zhì)量的測(cè)試代碼。

考慮重用代碼、使用協(xié)議、在多個(gè)測(cè)試中使用時(shí)定義屬性,并確保您的測(cè)試清理所有創(chuàng)建的數(shù)據(jù)。這將使您的單元測(cè)試更易于維護(hù),并防止不穩(wěn)定和奇怪的測(cè)試失敗。

100% 的代碼覆蓋率不應(yīng)該是你的目標(biāo)

盡管它是很多人的目標(biāo),但 100% 的覆蓋率不應(yīng)該是您編寫測(cè)試時(shí)的主要目標(biāo)。一個(gè)很好的開始是確保至少測(cè)試您最關(guān)鍵的業(yè)務(wù)邏輯。覆蓋率達(dá)到 100% 可能會(huì)很耗時(shí),而收益并不總是那么顯著。并且達(dá)到100%,也意味著可能需要付出很大的努力。

最重要的是,100% 的覆蓋率可能會(huì)產(chǎn)生誤導(dǎo)。上面的單元測(cè)試示例覆蓋了所有方法,覆蓋率為 100%。但是,它并沒有測(cè)試所有場(chǎng)景,因?yàn)樗粶y(cè)試了一個(gè)非空數(shù)組。同時(shí),也可能存在空數(shù)組的情況,其中 hasUsers 屬性應(yīng)該返回 false。

圖片

您可以從 Scheme 設(shè)置窗口啟用測(cè)試覆蓋率。這個(gè)窗口可以通過Product ? Scheme ? Edit Scheme打開。

在修復(fù)錯(cuò)誤之前編寫測(cè)試

跳到一個(gè)錯(cuò)誤上并盡快修復(fù)它是很誘人的。雖然這很好,但如果您可以防止將來再次出現(xiàn)相同的錯(cuò)誤,那就更好了。通過在修復(fù) bug 之前編寫單元測(cè)試,可以確保相同的 bug 不會(huì)再次發(fā)生。將其視為“測(cè)試驅(qū)動(dòng)的錯(cuò)誤修復(fù)”,從現(xiàn)在開始也稱為 TDBF 。

其次,您可以開始編寫修復(fù)程序并運(yùn)行新的單元測(cè)試來驗(yàn)證修復(fù)程序是否有效。此技術(shù)比運(yùn)行模擬器來驗(yàn)證您的修復(fù)是否有效要快。

結(jié)論

編寫定性的單元測(cè)試是開發(fā)人員的基本技能。將能夠?qū)δ拇a庫建立信心,確保您在新版本發(fā)布之前沒有破壞任何東西。使用正確的斷言,您可以更快地解決失敗的測(cè)試。確保至少測(cè)試關(guān)鍵業(yè)務(wù)代碼并避免達(dá)到 100% 的代碼覆蓋率。

責(zé)任編輯:武曉燕 來源: Swift君
相關(guān)推薦

2024-10-07 09:12:33

2023-07-26 13:11:21

ChatGPT平臺(tái)工具

2023-03-30 08:26:31

DNSTCPUDP

2022-11-02 07:37:07

WebAssembl瀏覽器服務(wù)器

2022-10-24 09:55:32

ESLintJavaScript

2023-03-31 08:16:39

CDN網(wǎng)絡(luò)數(shù)據(jù)

2023-04-26 00:41:36

A/B測(cè)試郵件數(shù)量

2023-01-26 00:28:45

前端測(cè)試技術(shù)

2024-01-02 12:05:26

Java并發(fā)編程

2023-08-01 12:51:18

WebGPT機(jī)器學(xué)習(xí)模型

2023-03-10 22:08:20

2024-03-01 08:13:45

Shell編程解釋器

2024-02-04 00:00:00

Effect數(shù)據(jù)組件

2024-01-19 08:25:38

死鎖Java通信

2023-01-10 08:43:15

定義DDD架構(gòu)

2023-08-01 07:27:42

Mockito測(cè)試Callback

2022-09-12 08:01:21

GreatSQLMySQL性能

2023-07-29 00:10:48

2023-12-07 07:03:09

2022-06-16 07:50:35

數(shù)據(jù)結(jié)構(gòu)鏈表
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)