
如果你是一位 Web 開發者,你可能早已習慣了現代前端測試的奢華體驗:
然而,當場景切換到 Windows 桌面端軟體開發(不論你是用 C++、C# / WPF / WinUI 3、Rust / Tauri,還是 Python 開發系統工具),測試的世界彷彿瞬間倒退了二十年:
「本地測試一切正常,推上 GitHub Actions
windows-latest卻神秘逾時失敗。」「打開 CI 日誌,只有一行冷冰冰的
TimeoutError: Element not found within 30.0s。」「CI 機器在雲端,沒有螢幕可以看,更沒有 RDP 可以連進去。你根本不知道那 30 秒內畫面上到底彈出了什麼鬼東西——是 Windows 的歡迎畫面?輸入法焦點跑了?還是背景視窗把焦點偷走了?」
這就是目前無數 Windows 桌面軟體開發者與 DevOps 工程師每天都在面對的 「CI 盲測黑盒子」。
這個系列不是讀完文件寫出來的教學。它源自一個真實的開源專案——ImeModePersistence:一款解決 Windows 輸入法在視窗切換時狀態跳掉的系統級工具,目前已上架 Microsoft Store。
為了保證它在廣大用戶電腦上穩定運行,我必須在 GitHub Actions CI 上進行嚴格的自動化驗證:
但在建置 CI 管道的第一週,我就撞上了無數隱形暗礁:
pywinauto、pyautogui)在面對 Windows 11 的現代應用生命週期(如 Store App 的 Shim 處理程序、XAML Island)時,較難直接進行深層走訪與非同步後置條件驗證。FindFirst 配 TreeScope_Descendants 跨不過那道邊界——同一個元素改用 RawViewWalker 手動走訪就找得到。在 ARM64 上實測三次都一致:FindFirst 約 200 ms 回報找不到,walker 4–7 ms 就拿到了。而因為探索會重試到逾時,使用者看到的是二十秒後的失敗。為了徹底解決這些問題,我從 Windows 底層 Win32 API、UI Automation(UIA)COM 介面、視訊串流編碼(PyAV)到虛擬桌面隔離機制全部重做了一遍,最終催生出開源桌面整合測試框架——wintegrate。
在自動化的 CI 上跑桌面測試,最痛苦的莫過於失敗時沒有畫面可看,只能看到一行 TimeoutError。如果每次報錯都要想辦法連 RDP 進去重現,不僅麻煩,而且那個當下的現場早就不見了。
所以設計測試流程時,最核心的考量就是 「自動把現場記錄下來」。當 CI 跑完或中途失敗時,自動在 artifacts/ 資料夾留下四樣診斷檔案:
📁 artifacts/
├── session_recording.mp4 # 1. 操作過程錄影(PyAV 串流寫入,不佔爆記憶體)
├── window_census.json # 2. 測試前後桌面視窗清單(比對是哪個彈窗搶了焦點)
├── session_events.json # 3. 動作事件時間軸
└── failure_screenshot.png # 4. 失敗當下的全螢幕截圖(涵蓋所有螢幕)
有了這些產物,當 CI 上的測試在凌晨三點掛掉時,你不用手忙腳亂去開遠端連線,只要在 GitHub Actions 下載 Artifacts:
session_recording.mp4,用 10 秒看一眼它是在哪一步卡住。window_census.json,比對一下是不是背景突然跳出了沒被關閉的系統通知。session_events.json,精確確認每一筆按鍵與點擊的時序。這四個檔案就是這個系列反覆要回答的那個問題的答案:在一台你連不進去的機器上,測試到底發生了什麼事?
適合這樣的讀者:寫 Windows 桌面應用、而且已經有(或想要有)CI 的人。 你不需要會 Python 以外的語言——雖然工具是 Python 寫的,但踩到的坑是 Win32 和 UIA 層級的,換成 C# 的 FlaUI 或 C++ 直接呼叫 UIA COM 一樣會遇到。
明天要拆的是一種不會留下錯誤訊息的失敗:你的程式碼全部執行成功,沒有任何例外,而畫面上什麼都沒發生。 那不是 bug,是你對著錯的那張桌面說話 —— 而 Windows 有三層桌面可以讓你站錯。