SwiftUI 頁面可以正常顯示,按下加分卻讓分數算錯,是新手專案常見的落差。
最快解法:先把可驗證的邏輯從畫面拆開,再放進 Xcode 27 的測試目標,用 Swift Testing 檢查結果;單元測試通過不代表介面互動也已驗收。

第一次替 SwiftUI 課程專案寫單元測試、還不熟悉 Xcode 測試目標的學生,可以照步驟完成第一個測試。
已能執行專案、但想確認資料處理或狀態變化是否正確的自學者,也適合從這裡開始。
使用學校或遠端 Mac 跟課、需要保存可重複測試結果的學習者,還可以參考最後的環境驗收方式。

01

先挑一段離開畫面也能檢查的邏輯

測試不是替整個畫面打分,而是確認一段程式在指定條件下有沒有得到預期結果。想像練習 App 顯示分數正確,但按一次「加分」後,內部狀態多加了不該有的數值:光看初始畫面,這個錯誤可能不會被發現。

先找一個輸入和輸出清楚的功能,例如計數器加分、表單輸入檢查,或切換一個狀態。若計算寫在 View 的按鈕事件中,可先抽成獨立型別或函式;畫面只負責呼叫它並呈現結果,測試則直接檢查結果。

這一步的判斷方式很直觀:輸入能否明確準備、操作能否單獨執行、結果能否直接檢查?若三者都清楚,就適合作為第一個單元測試對象。單元測試可先理解成「只檢查一小段功能的作業」;斷言則像判分條件,明確寫出預期答案。

Swift Testing 怎麼替 SwiftUI 邏輯寫第一個單元測試?先準備輸入,再呼叫被測邏輯,最後用預期條件確認答案。Apple 的 Swift Testing 記分應用教學也以小型功能示範加入測試;這裡用同樣清楚的「準備、執行、檢查」思路,但不要求先測整個畫面。

struct ScoreCounter {
    private(set) var score = 0

    mutating func addPoint() {
        score += 1
    }
}

這段型別不依賴 SwiftUI 畫面。測試只需建立計數器、執行 addPoint(),再檢查分數是否符合預期,便能把「加分錯誤」和按鈕是否顯示分開處理。

02

在 Xcode 27 確認測試程式放對位置

測試目標(test target)是 Xcode 專案中專門編譯與執行測試的區域;可以把它想成作業的測驗場地。測試程式放在 App 的一般程式碼中,不一定會被測試執行器辨識,因此建立或接手專案時,先確認檔案所屬目標,再開始寫測試。

Apple 的Xcode 專案新增測試說明及設定專案目標文件可用來核對專案結構。Xcode 27 的實際畫面與選項名稱應以目前安裝版本及官方文件為準,不要只依照不同版本的教學截圖猜路徑。

Swift Testing 測試檔案應該放在哪個測試目標?放在該專案用來執行測試的測試目標,並確認測試檔有加入該目標;不要只看檔案是否出現在左側清單。Apple 的 Swift Testing 框架說明提供框架資訊,新增測試目標時則以專案目前的設定為準。

開始前,按以下順序檢查:

  • 在專案導覽區選取測試檔,確認檔案所屬目標包含測試目標。
  • 確認測試程式匯入 Testing,而不是只把測試程式碼貼進 App 的畫面檔案。
  • 確認測試所呼叫的型別或函式,能由測試目標存取。
  • 對照 Apple 的Xcode 系統需求,核對目前 Xcode 版本與使用中的 macOS 環境是否相容。
03

寫下測試,然後從 Xcode 執行

以下程式碼示範 Swift Testing 的基本結構。@Test 標記測試函式,#expect 表達需要成立的預期條件;Apple 的預期條件文件說明這類檢查方式。範例中的分數是教學用輸入,不是效能或實測資料。

import Testing

@Test
func addingPointIncreasesScore() {
    var counter = ScoreCounter()

    counter.addPoint()

    #expect(counter.score == 1)
}

操作順序就是準備計數器、呼叫加分方法、檢查結果。若課程專案中的邏輯不需要修改內部狀態,則不必照抄 var 或 mutating;應以實際函式的輸入與輸出調整測試。

在 Xcode 中,先依目前版本的官方說明確認測試目標已建立,再從專案提供的測試操作啟動測試。Apple 的執行測試與解讀結果文件可協助確認執行方式和結果檢視位置。通過表示這項預期條件成立;失敗則先讀取指出的測試與檢查條件,再回到程式逐項比對。

測試程式沒有出現在測試結果中時,先查檔案是否加入正確測試目標、是否匯入 Testing,以及函式是否符合 Swift Testing 的宣告方式。這些檢查比未經驗證地清除快取或重裝工具更直接。

為什麼 SwiftUI 頁面能執行,Swift Testing 卻沒有發現測試?頁面能啟動只代表 App 有可執行的內容,不代表測試檔已納入測試目標。若測試完全沒有列出,先檢查檔案歸屬、框架匯入和測試函式宣告;若測試有列出但失敗,再分辨是測試輸入、預期答案,還是實際邏輯不符。

04

依測試結果分流,不要把失敗都當成同一種問題

測試未被發現,與測試執行後答案不符,是兩種不同狀況。前者先查專案設定和測試宣告;後者則從輸入開始核對:測試送進去的值是否正確、預期結果是否符合需求、被測程式是否真的按規則運作。

若失敗訊息指向預期條件,先不要急著改測試讓它通過。回到課程規格確認正確答案,再檢查函式的每一步。例如,需求若是「輸入符合規則才更新狀態」,就要同時確認允許的輸入與不允許的輸入各自會發生什麼事。

單元測試通過後,還需要用模擬器檢查介面嗎?需要。Swift Testing 可以驗證獨立邏輯,但不會因此證明按鈕位置、畫面更新或操作流程符合課程要求;介面仍應在 App 中另行執行與檢查。

05

用表格完成課程驗收與環境選擇

先用下表決定要測哪一層。功能邏輯與畫面互動的驗收目的不同,不能互相替代。

要確認的項目 建議方式 能回答的問題 不能單獨證明的事
計算、輸入檢查、狀態變化 Swift Testing 單元測試 指定條件下邏輯結果是否符合預期 畫面操作是否順暢
按鈕與畫面更新 執行 App 並操作介面 點擊後畫面是否依需求改變 所有邏輯邊界都正確
課程規定的提交或驗收 依課程要求檢查 作業是否符合指定提交條件 未列入驗收範圍的功能

整理測試目標時,可以用這張核對表避免把「有檔案」誤認成「測試已就緒」:

專案情況 核對方向 下一步
新建專案已包含測試設定 確認測試檔隸屬哪個測試目標,並確認匯入的框架 在既有測試區加入小型邏輯測試
既有專案沒有可用測試目標 依 Apple 文件檢查新增目標的設定與專案關聯 確認目標建立後,再將測試檔加入其中
測試檔存在但結果中沒有測試 查檔案目標、Testing 匯入與函式宣告 修正測試發現問題後再執行

課程練習可以從正常輸入和一個有代表性的邊界情形開始。邊界情形就是容易被忽略、但會改變結果的條件,例如空白輸入、允許範圍的臨界值,或計數器目前已處於某個特殊狀態。選擇哪種情形,要依功能規格決定,而不是為了增加測試數量而任意添加。

驗收結果 可以得出的結論 還要做什麼
Swift Testing 通過 已檢查的邏輯條件符合預期 另行執行 App,檢查介面互動
App 可在模擬器執行 目前執行環境可啟動該 App 依課程規定確認是否還要真機驗收
課程指定的驗收完成 已符合課程列出的驗收要求 保存測試結果及必要的作業資料

若使用學校提供的 Mac,先確認允許使用 Xcode、執行測試並保存專案;若課程指定真機驗收,也要另行確認設備與課程流程。沒有相容 Mac 時,可先參考沒有 Mac 學習 iOS 開發的環境選擇,再依課程要求挑選可執行 Xcode 的環境。若需要進一步了解遠端 Mac 的使用方案,可查看遠端 Mac 方案與購買選擇。Xcode 版本與 macOS 相容性,仍應以官方系統需求為準。

如果目前方案是只用 Windows,限制是無法原生執行 Xcode;如果依賴共享的學校電腦,使用時段和軟體安裝權限可能受管理;若嘗試虛擬化環境,還需自行確認相容性與課程要求。當練習需要可重複使用的 macOS 開發環境、但暫時不想購買 Mac,NodeMini 的遠端 Mac 可作為按需使用的選項;它適合短期跟課和測試練習,若要長期固定重負載工作或必須直接連接實體設備,則應先評估自有 Mac 是否更合適。