付費限定

🔀UUID 的隨機特性很好,測試的困難就交給 Swift Dependencies

13-avatar-img
發佈於📦 推薦 Swift Package 個房間
更新於 發佈於 閱讀時間約 12 分鐘

上一篇 Swift Dependencies 文章以 Date 為範例,相信讀者已經體會到,即使是時間這麼基本的型別,也可以造成測試上的困難。而 Swift Dependencies 可以在測試環境下,替換掉當下的系統時間,使得測試時的行為能夠符合預期。

在這篇文章中,我們繼續延伸昨天的例子,加深印象的同時多介紹一點概念。

在一個筆記 app 中,指定 id 來存取特定一篇筆記,是很常見的需求。所以,我們打算把 Note 加上 id 欄位,並且使用 UUID 型別,以確保唯一性。

UUID 唯一性的用途

UUID 的特性就是在產生時會有唯一性、不會重複。這對於確保資料之間不會衝突,是非常好的特性。

但是,如果我們直接寫 let id = UUID(),就會跟上一篇的 Date() 發生一樣的問題──無法控制產生的結果。

struct Note {  // v5
let id = UUID() // 新增 id 欄位,隨機產生
let createdDate: Date
var modifiedDate: Date
var text: String = "" {
didSet {
@Dependency(\.date.now) var date
modifiedDate = date
}
}

init() {
@Dependency(\.date.now) var date
self.createdDate = date
self.modifiedDate = date
}
}

不控制 UUID 產生的結果,就不好測試

大部分情況,其實我們並不在意 UUID 的值,因為相信系統會做到產生唯一、不衝突的值,就夠了。

但假如我們把它當成某個關鍵邏輯的參考依據,那麼這種隨機特性,就會讓測試失敗。

舉例來說,我們會想要筆記有個穩定的排序規則,依照 modifiedDatetextid 這三個條件。理論上時間與內文是有可能重複的(比如我們做了複製同一則筆記的功能),所以最後就以 id 為依據。

我們可以幫 Note 簡單地實作 Comparable protocol。如果你不熟悉這個比較 tuple 的語法,簡單來說它會由左到右依序比對 modifiedDatetext、最後才是 id

extension Note: Comparable {
static func < (lhs: Self, rhs: Self) -> Bool {
(lhs.modifiedDate, lhs.text, lhs.id) < (rhs.modifiedDate, rhs.text, rhs.id)
}
}

但是在測試時,無法得到穩定的結果。

@Test(
"[non-deterministic] Ensure note default sorting order - will fail randomly"
)
func sortNotesWillFail() {
let notes = withDependencies {
$0.date.now = .init(timeIntervalSinceReferenceDate: 0)
} operation: {
[Note(), Note(), Note()]
}

let sorted = notes.sorted(by: <)

// UUID() 是隨機的,即使 `modifiedDate`、`text` 相同,也無法預測排序後的順序
#expect(notes == sorted)
#expect(notes[0] == sorted[0])
}
💡技術細節:
各種程式語言的 UUID 主要是參照 RFC 4122,並且有多種版本。

有幾個版本的 UUID,具備 time-ordered 的特性(例如 UUIDv7),產出的 id 直接當字串來排序,就具備時間遞增的效果。這類 UUID 能兼顧唯一性與遞增排序,特別適用於一些資料庫的應用。

而 Swift Foundation 的 UUID 是依照 RFC 4122 version 4 的規格產生的。它會參考當下時間產生,但是產出的隨機字串並沒有遞增特性。所以連續呼叫的 UUID() 的結果,不會是穩定的順序。

透過 Swift Dependencies 的 UUIDGenerator 來控制產生結果

就像 DateSwift Dependencies 也內建 UUID 的注入方式。方法是:@Dependency(\.uuid) var uuid

以行動支持創作者!付費即可解鎖
本篇內容共 4467 字、0 則留言,僅發佈於💡 實用技巧、📦 推薦 Swift Package你目前無法檢視以下內容,可能因為尚未登入,或沒有該房間的查看權限。
留言
avatar-img
留言分享你的想法!
avatar-img
13+
1.4K會員
79內容數
13 以 10+ 年 iOS 開發經驗為基礎撰寫,助你在 AI 時代成為更有自信的技術工作者。 ❤️ 支持 13 創作! 🤖 AI 工具實戰經驗與深度思考 🧠 軟體開發思維、職涯發展建議 💡 實用技巧與踩坑經驗分享 😔 開發者身心健康與職業傷害
13+的其他內容
2025/09/07
Swift Dependencies 是我最常使用的套件。它讓外部條件變成完全可控,解決了測試困難和 SwiftUI Preview 編譯緩慢的問題。使用它以後,我在區分元件職責、設計測試的功力都大幅提升。
Thumbnail
2025/09/07
Swift Dependencies 是我最常使用的套件。它讓外部條件變成完全可控,解決了測試困難和 SwiftUI Preview 編譯緩慢的問題。使用它以後,我在區分元件職責、設計測試的功力都大幅提升。
Thumbnail
2025/08/28
下載官方 App、預習活動時間表與交通資訊、提前抵達,用愉快的心情享受兩天的活動!
Thumbnail
2025/08/28
下載官方 App、預習活動時間表與交通資訊、提前抵達,用愉快的心情享受兩天的活動!
Thumbnail
2025/08/27
即使在現實中不擅長聊天,也可以享受研討會的互動。稍微做點準備即可!不論社交能力如何,這篇文章談到的準備適用於任何人。
Thumbnail
2025/08/27
即使在現實中不擅長聊天,也可以享受研討會的互動。稍微做點準備即可!不論社交能力如何,這篇文章談到的準備適用於任何人。
Thumbnail
看更多
你可能也想看
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
這篇文章探討瞭如何在iOS應用程式中客製化Alert,包括改變字體大小、內嵌連結以及讓Alert的高度隨著字數增長並提供scroll操作。同時使用SwiftUI進行客製化,並介紹瞭解決高度超出範圍後文字捲動與scrollView固定高度的方法。
Thumbnail
這篇文章探討瞭如何在iOS應用程式中客製化Alert,包括改變字體大小、內嵌連結以及讓Alert的高度隨著字數增長並提供scroll操作。同時使用SwiftUI進行客製化,並介紹瞭解決高度超出範圍後文字捲動與scrollView固定高度的方法。
Thumbnail
本文介紹瞭如何在SwiftUI中調整元件的對齊方式,包括置中、向左/向右/向上/向下對齊的方法。透過調整HStack、VStack以及frame的maxWidth、maxHeight和alignment屬性,可以達到想要的對齊效果。
Thumbnail
本文介紹瞭如何在SwiftUI中調整元件的對齊方式,包括置中、向左/向右/向上/向下對齊的方法。透過調整HStack、VStack以及frame的maxWidth、maxHeight和alignment屬性,可以達到想要的對齊效果。
Thumbnail
本文檔介紹了在Swift中使用套件的詳細方法,包括如何引用第三方套件和自定義模組,如何創建自定義套件,以及一些常見的Swift套件。這些套件可以幫助開發者快速添加功能到項目中,提高開發效率和程式碼品質。
Thumbnail
本文檔介紹了在Swift中使用套件的詳細方法,包括如何引用第三方套件和自定義模組,如何創建自定義套件,以及一些常見的Swift套件。這些套件可以幫助開發者快速添加功能到項目中,提高開發效率和程式碼品質。
Thumbnail
本章節介紹了如何建立並設置Swift項目以及如何選擇和設置Swift代碼編輯器。這包括在Xcode和命令行中建立Swift項目,選擇Xcode、Visual Studio Code或AppCode作為編輯器,以及如何使用SPM安裝插件。
Thumbnail
本章節介紹了如何建立並設置Swift項目以及如何選擇和設置Swift代碼編輯器。這包括在Xcode和命令行中建立Swift項目,選擇Xcode、Visual Studio Code或AppCode作為編輯器,以及如何使用SPM安裝插件。
Thumbnail
這份文件的目的是介紹Swift語言,包括它的特性、應用範疇,以及誰在使用它。它也提供了一些學習Swift的資源和工具,以及一些常見的Swift庫和框架。
Thumbnail
這份文件的目的是介紹Swift語言,包括它的特性、應用範疇,以及誰在使用它。它也提供了一些學習Swift的資源和工具,以及一些常見的Swift庫和框架。
Thumbnail
需求情境: 在設計畫面時,資料來源是後台的 api,每一次畫面細節的修修改改,都會觸發 Xcode Preview 程序,導致不斷呼叫後台。此時若資料結構和大小都具有一定規模,就會導致效率低落,不斷等待,且消耗伺服器資源甚鉅。 解決方案: 將後台傳回的資料以檔案形式暫存在本地端,每次 pr
Thumbnail
需求情境: 在設計畫面時,資料來源是後台的 api,每一次畫面細節的修修改改,都會觸發 Xcode Preview 程序,導致不斷呼叫後台。此時若資料結構和大小都具有一定規模,就會導致效率低落,不斷等待,且消耗伺服器資源甚鉅。 解決方案: 將後台傳回的資料以檔案形式暫存在本地端,每次 pr
Thumbnail
Part.1 搞定基本的 UI 開始開發 iOS App。 首先準備一台 Mac,然後安裝 Xcode,新增專案,系統即刻生成基本的專案結構。coding 的起點在檔案 ContentView.swift: import SwiftUI struct ContentView: View {  
Thumbnail
Part.1 搞定基本的 UI 開始開發 iOS App。 首先準備一台 Mac,然後安裝 Xcode,新增專案,系統即刻生成基本的專案結構。coding 的起點在檔案 ContentView.swift: import SwiftUI struct ContentView: View {  
Thumbnail
只是 Swift 以 language level 支援 Optional 確實比用 API level 支援的 Java 要簡潔和更具可讀性。Swift 作為一個全新的語言,從一開始的設計就將許多好的語言特性加入,確實讓人驚豔。
Thumbnail
只是 Swift 以 language level 支援 Optional 確實比用 API level 支援的 Java 要簡潔和更具可讀性。Swift 作為一個全新的語言,從一開始的設計就將許多好的語言特性加入,確實讓人驚豔。
Thumbnail
在寫SwiftUI view的時候,碰到一個瓶頸(? 帶有Binding的參數要如何preview。 舉例來說有個右邊圖片左邊文字的View,給他一個@Binding var isActive: Bool的狀態,當active時圖片要跟著改變: struct RightImageView: Vie
Thumbnail
在寫SwiftUI view的時候,碰到一個瓶頸(? 帶有Binding的參數要如何preview。 舉例來說有個右邊圖片左邊文字的View,給他一個@Binding var isActive: Bool的狀態,當active時圖片要跟著改變: struct RightImageView: Vie
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News