Skip to content

Compose Multiplatform UI 測試環境設定與疑難排解

Yu-Chan (Henry) Huang edited this page May 23, 2026 · 3 revisions

在重構 OmniHub 專案並導入 runComposeUiTest 時,我們在 WasmJS 與 Android Host Test 平台上遇到了一些環境配置導致的測試失敗。本文件記錄了這些問題的原因與修復方法。

1. WasmJS: 編譯與 Webpack 警告

為什麼會錯?

WasmJS 平台在執行測試時,會透過 Webpack 進行打包。由於 Compose 的圖形引擎 (Skiko) 使用了動態依賴載入,導致 Webpack 無法進行靜態分析並噴出警告。此外,Kotlin 2.0+ 對於 WasmJS 的互操作性 (Interop) 有更嚴格的實驗性 API 限制。

錯誤訊息

  • Critical dependency: the request of a dependency is an expression
  • This declaration needs opt-in. Its usage should be marked with '@kotlin.js.ExperimentalWasmJsInterop'

如何解決?

  1. 忽略 Webpack 警告: 在 shared/src/wasmJsMain/resources/webpack.config.d/config.js 加入腳本,強制 Webpack 忽略 Skiko 引起的動態依賴警告。
  2. 開啟編譯器許可: 在 shared/build.gradle.kts 的 wasmJs 區塊中加入編譯參數:
    wasmJs {
        compilerOptions {
            freeCompilerArgs.add("-opt-in=kotlin.js.ExperimentalWasmJsInterop")
        }
    }

2. Android Host Test: Robolectric 環境配置

為什麼會錯?

當 UI 測試寫在 commonTest 並在 Android Target 上執行時,如果是在電腦的 JVM 上跑(而非實體機),這被稱為 Host Test。純 JVM 並不具備 Android 的系統屬性與 Activity 執行環境。

錯誤訊息

  1. NPE: Cannot invoke "String.toLowerCase()" because "android.os.Build.FINGERPRINT" is null
    • 原因:runComposeUiTest 試圖讀取 Android 系統資訊,但純 JVM 環境沒有這些資料。
  2. RuntimeException: Unable to resolve activity for Intent { ... ComponentActivity }
    • 原因:測試環境找不到可以承載 UI 的 Activity 宣告。

如何解決?

步驟 A:引入 RobolectricBase Class 模式

  • 由於 JUnit 4 不支援透過自定義註解傳遞 @RunWith,我們採用 expect/actual 建立 BaseComposeTest 抽象類別: Android 端 (actual): 標註 @RunWith(RobolectricTestRunner::class),強制在模擬的 Android 環境下執行。
  • 其餘平台 (actual): 保持為空的實作。

步驟 B:補齊 Activity 宣告

  1. 依賴:加入 androidx.compose.ui:ui-test-manifest
  2. Manifest:在 shared/src/androidDebug/AndroidManifest.xml 中手動宣告 androidx.activity.ComponentActivity
  3. 配置:在測試基底類別中指定 packageName
    @Config(sdk = [35], packageName = "io.lackstudio.omnihub.shared")
    actual abstract class BaseComposeTest

總結:平台測試檢查表

如果你在新增 UI 測試時遇到類似錯誤,請檢查以下設定:

平台 必要設定
Android 繼承 BaseComposeTes (Robolectric), 確保 androidDebug 有 Manifest
WasmJS webpack.config.d 腳本, ExperimentalWasmJsInterop opt-in
iOS / JVM 直接繼承 BaseComposeTest 即可運作