SwiftUI 框架

在 SwiftUI 中 利用 ViewInspector 框架測試包含 @State 的視圖

這個小技巧可以簡化測試 SwiftUI 視圖的步驟,讓你了解如何利用 ViewInspector 框架進行 SwiftUI 測試。
在 SwiftUI 中 利用 ViewInspector 框架測試包含 @State 的視圖
在 SwiftUI 中 利用 ViewInspector 框架測試包含 @State 的視圖
In: SwiftUI 框架
本篇原文(標題:How to Test SwiftUI Views Containing @State in ViewInspector)刊登於作者 Medium,由 Dragos Ioneanu 所著,並授權翻譯及轉載。

你可以先參閱這篇這篇文章,來了解利用 ViewInspector 框架進行 SwiftUI 測試。

在第一篇教學文章及 ViewInspector 的 GitHub 頁面中,就有提到如何在想要測試的視圖中使用 @State

假設我們的視圖是這樣的:

struct ContentView: View {
   @State var numClicks:Int = 0
 
   var body: some View {
      VStack{
         Button("Click me"){
            numClicks += 1
         }.id("Button1")
         Text("\(numClicks)")
           .id("Text1")
           .padding()
   
      }
   }
}

我們其實是無法在 numClicks 測試單擊按鈕的動作。

要解決這個問題,我們就要在視圖中添加一些程式碼,將其轉換為:

struct ContentView: View {
   @State var numClicks:Int = 0
   internal let inspection = Inspection<Self>()
 
   var body: some View {
      VStack{
         Button("Click me"){
            numClicks += 1
         }.id("Button1")
         Text("\(numClicks)")
           .id("Text1")
           .padding()
   
       }.onReceive(inspection.notice) { 
            self.inspection.visit(self, $0) }
    }
}

而 Inspection 就在這裡:

internal final class Inspection<V> {
   let notice = PassthroughSubject<UInt, Never>()
   var callbacks: [UInt: (V) -> Void] = [:]
   func visit(_ view: V, _ line: UInt) {
      if let callback = callbacks.removeValue(forKey: line) {
         callback(view)
      }
   }
}
extension Inspection: InspectionEmissary {}

從上面的程式碼可見,ContentView 有一個新的 Inspection 屬性 (property),當數據 publish 到 noticed publisher 時,就會指示 body 的 onReceive 執行 Inspection 屬性的 visit 方法。

這樣問題就解決了,我們可以這樣編寫一個測試範例:

func testContentView() throws{
   let sut = ContentView()
    _ = sut.inspection.inspect { view in
       let button = try view.find(viewWithId: “Button1”).button()
       try button.tap()
       XCTAssertEqual(try view.actualView().numClicks, 1)
       let text = try view.find(viewWithId: “Text1”).text()
       let value = try text.string()
       XCTAssertEqual(value, “1”)
    }
 }

不過,把測試「功能」添加到 production code 不太好看,可能會讓複雜的視圖變得更複雜,而且會需要在每個要測試的視圖中,複製/貼上大量多餘的程式碼。

因此,我嘗試尋找更簡潔的方法。這個方法可能會讓 testing code 多了幾層,但就不用變更實際的視圖實作。

首先,讓我們實作一個簡單的包裝器 (wrapper) 視圖,這樣可以添加 ViewInspector 需要的 Inspection 功能:

public let TEST_WRAPPED_ID: String = "wrapped"

struct TestWrapperView<Wrapped: View> : View{
   internal let inspection = Inspection<Self>()
   var wrapped: Wrapped
 
   init( wrapped: Wrapped ){
       self.wrapped = wrapped
   }
 
   var body: some View {
      wrapped
        .id(TEST_WRAPPED_ID)
        .onReceive(inspection.notice) { 
           self.inspection.visit(self, $0) 
        }
    }
}

extension TestWrapperView: Inspectable{}

有了這個包裝器視圖,我們就可以使用原本實作的 ContentView 來測試視圖:

func testContentView() throws{
   let sut = TestWrapperView(wrapped: ContentView())
   _ = sut.inspection.inspect { view in
       let wrapped = try view.find(viewWithId: TEST_WRAPPED_ID)
       let button = try wrapped.find(viewWithId: “Button1”).button()
       try button.tap()
       let numClicks = try wrapped
                         .view(ContentView.self)
                         .actualView()
                         .numClicks
       XCTAssertEqual(numClicks, 1)
       let text = try wrapped.find(viewWithId: “Text1”).text()
       let value = try text.string()
       XCTAssertEqual(value, “1”)
    }
 }

這個小技巧可以簡化測試 SwiftUI 視圖的步驟,希望大家喜歡這篇文章。

本篇原文(標題:How to Test SwiftUI Views Containing @State in ViewInspector)刊登於作者 Medium,由 Dragos Ioneanu 所著,並授權翻譯及轉載。
譯者簡介:Kelly Chan-AppCoda 編輯小姐。
作者
AppCoda 編輯團隊
此文章為客座或轉載文章,由作者授權刊登,AppCoda編輯團隊編輯。有關文章詳情,請參考文首或文末的簡介。
評論
更多來自 AppCoda 中文版
如何使用 Vision APIs 從圖像中辨識文字
AI

如何使用 Vision APIs 從圖像中辨識文字

Vision 框架長期以來一直包含文字識別功能。我們已經有詳細的教程,向你展示如何使用 Vision 框架掃描圖像並執行文字識別。之前,我們使用了 VNImageRequestHandler 和 VNRecognizeTextRequest 來從圖像中提取文字。 多年來,Vision 框架已經顯著演變。在 iOS 18 中,Vision
iOS 18更新:SwiftUI 新功能介紹
SwiftUI 框架

iOS 18更新:SwiftUI 新功能介紹

SwiftUI的技術不斷演進,每次更新都讓 iOS 應用程式開發變得更加便捷。隨著 iOS 18 Beta 的推出,SwiftUI 引入了多個令人興奮的新功能,使開發者僅需幾行程式碼即可實現出色的效果。 本教學文章旨在探索這個版本中的幾項主要改進,幫助你了解如何運用這些新功能。 浮動標籤列 (Floating Tab Bar)SwiftUI中的標籤視圖(Tab
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。