Flutter 測試中的插件
幾乎所有 Flutter 插件 都包含兩個部分:
- Dart 程式碼,提供您的程式呼叫的 API。
- 以平台專屬(或稱「host」)語言(如 Kotlin 或 Swift)撰寫的程式碼,負責實作這些 API。
事實上,原生(host)語言的程式碼正是區分插件套件與標準套件的關鍵。
建置並註冊插件的 host 部分,是 Flutter 應用程式建置流程的一部分, 因此插件僅在您的程式碼於應用程式中執行時才會運作,例如使用 flutter run 或執行 整合測試 時。 當執行 Dart 單元測試 或 元件測試 時,host 程式碼並不可用。 如果您正在測試的程式碼有呼叫任何插件, 通常會導致如下錯誤:
MissingPluginException(No implementation found for method someMethodName on channel some_channel_name)當你在單元測試中測試使用 plugin 的程式碼時, 有幾種方式可以避免這個例外。 以下解決方案依推薦順序排列。
將 plugin 呼叫包裝起來
#在大多數情況下,最佳做法是將 plugin 的呼叫包裝在你自己的 API 中, 並在測試時提供 mock 你自己 API 的方式。
這麼做有幾個優點:
- 如果 plugin 的 API 有變動, 你不需要更新測試。
- 你只會測試自己的程式碼, 測試不會因為你所使用的 plugin 行為而失敗。
- 不論 plugin 的實作方式為何, 甚至是非 plugin 的套件依賴, 你都可以用相同的方式進行測試。
Mock plugin 的公開 API
#如果 plugin 的 API 已經是基於類別實例, 你可以直接 mock 它,但需注意以下事項:
- 如果 plugin 使用的是非類別函式或靜態方法, 這種方式將無法運作。
- 當 plugin API 變動時, 測試也需要跟著更新。
Mock plugin 的平台介面
#如果 plugin 是 federated plugin, 它會包含一個平台介面(platform interface), 允許註冊其內部邏輯的實作。 你可以註冊該平台介面的 mock 實作, 而不是 mock 公開 API,但需注意以下事項:
- 如果 plugin 不是 federated plugin,這種方式將無法運作。
- 你的測試會包含部分 plugin 的程式碼, 因此 plugin 的行為可能會對你的測試造成影響。 例如,如果某個 plugin 會在內部快取時寫入檔案, 你的測試行為可能會因為是否曾經執行過而改變。
- 當平台介面變動時,測試可能也需要更新。
這種方式可能必要的情境是: 你依賴的某個套件使用了 plugin, 而不是你自己的程式碼, 因此你無法改變呼叫方式。 不過,如果可能的話, 你應該 mock 那個使用 plugin 的依賴,而不是直接 mock plugin。
Mock 平台通道(platform channel)
#如果 plugin 使用 平台通道(platform channels), 你可以使用 TestDefaultBinaryMessenger 來 mock 這些平台通道。 只有在上述方法都不可行時,才建議使用這種方式, 因為它有以下幾個缺點:
- 只有使用平台通道實作的 plugin 才能被 mock。 這代表如果有些實作沒有用到平台通道, 你的測試在某些平台上會意外地使用到真實實作。
- 平台通道通常是 plugin 的內部實作細節。 即使是 plugin 的 bugfix 更新,也可能大幅更動, 造成測試意外失敗。
- 在 federated plugin 的每個實作中,平台通道可能不同。 例如,你可能設置了 mock 平台通道, 讓測試在 Windows 機器上通過, 但在 macOS 或 Linux 上執行時卻失敗。
- 平台通道並非強型別。 例如,method channel 通常使用字典(dictionary), 你必須閱讀 plugin 的實作才能知道 key 字串與 value 型別。
由於這些限制,TestDefaultBinaryMessenger 主要適用於 plugin 實作本身的內部測試, 而不是用於測試使用 plugin 的程式碼。
你也可以參考 Testing plugins。