iT邦幫忙

2026 iThome 鐵人賽

DAY 12
0
Build on Google AI

將考國際證照的應用程式變成開源系列 第 17

test-spec : 01-test-strategy , 02-unit-tests , 03-widget-tests

  • 分享至 

  • xImage
  •  

01-test-strategy.md

測試策略規範

目標讀者:AI 代理(規範解析)與人類 QA/開發人員。
背景:本文檔定義了認證考試題庫應用程式的測試策略。例如,在一個網路考試應用程式中,這些策略可確保題目、網路邏輯(如 IP 位址計算)及使用者進度的可靠性。

1. 測試金字塔

本專案遵循標準測試金字塔,以平衡執行速度與信心水準:

  • 單元測試 (70%):專注於 Models、Services、Controllers、Repositories 及 Utils。這些測試在隔離環境中執行,不依賴 UI。
  • 元件測試 (Widget Tests, 20%):確保 UI 元件、畫面渲染及使用者互動在無頭 (headless) 環境中運作正常。
  • 整合/端到端測試 (10%):驗證完整使用者流程與跨服務互動,於模擬器或實體裝置上執行。

2. 工具鏈

  • flutter_test:內建的單元與元件測試框架。
  • mockito / mocktail:用於產生模擬類別 (Mock) 及模擬依賴項。
  • flutter_gherkin:用於行為驅動開發 (BDD) 測試執行與定義 Feature 檔案。
  • integration_test:官方的端到端 (E2E) 測試套件。
  • golden_toolkit:(選用)用於跨不同螢幕尺寸的像素級截圖測試。

3. 測試環境

  • Mock Repository 注入:透過 RepositoryFactory.setMockRepository() 在元件與控制器測試中注入模擬資料來源。
  • Firebase Emulator Suite:用於身分驗證與即時資料庫測試的本機模擬器,避免影響正式環境資料。
  • 記憶體內資料庫 (In-Memory):用於 PowerSync 本機 SQLite 同步測試。
  • RevenueCat Sandbox:使用測試 API 金鑰與沙盒環境進行 App 內購買驗證。

4. 覆蓋率目標

我們的目標程式碼覆蓋率指標如下:

  • Models:100%(對資料完整性至關重要)
  • Services:80%+(商業邏輯層)
  • Controllers:90%+(狀態管理)
  • Repositories:85%+(資料存取層)
  • Widgets:60%+(核心 UI 元件)
  • Screens:40%+(主要透過整合/E2E 測試涵蓋)

5. CI 整合

  • Pre-commit:提交前必須通過 flutter analyze libflutter test(單元/元件測試)。
  • PR Gate:在 GitHub Actions 上執行完整測試套件並產生覆蓋率報告。未達覆蓋率標準的 PR 將被阻擋。
graph TD
    A["提交程式碼"] --> B["Pre-commit Hooks"]
    B -->|通過| C["推送到 GitHub"]
    C --> D["GitHub Actions CI"]
    D --> E["Linter 與格式化"]
    D --> F["單元與元件測試"]
    D --> G["整合測試 (Firebase 模擬器)"]
    F --> H["覆蓋率報告"]
    H --> I{"達到目標?"}
    I -->|是| J["允許合併"]
    I -->|否| K["阻擋 PR"]

02-unit-tests.md

單元測試規範

目標讀者:AI 代理與 QA 工程師。
背景:核心通用認證考試模組的全面單元測試,涵蓋封包邏輯與通用題型。

1. Models 測試 (約 25 個案例)

測試 ID 描述 輸入 預期輸出 邊界案例
MDL-001 Question.fromMap: 單選題解析 Map 帶有 type: SINGLE_CHOICE Question 物件,正確解析單一答案 缺少選項陣列
MDL-002 Question.fromMap: 多選題 Map 帶有 correctAnswer: [0, 2] 正確解析 List<int> correctAnswer 列表為空
MDL-003 Question.fromMap: 拖放題 Map 包含 dragOptionsdropTargets 陣列對應正確 選項與目標數量不符
MDL-004 Question.fromMap: 模擬題 Map 包含 practicalSolution 解析出文字指令 solution 欄位為 null
MDL-005 Question.fromMap: 缺少可選欄位 Map 省略 images, videoUrl 物件解析為 null 整個 Map 為空
MDL-006 Question.toMap: 序列化來回測試 有效的 Question 物件 完全相等的 Map 所有可選欄位皆為 null 的物件
MDL-007 Question.copyWith: 部分欄位更新 question.copyWith(title: '新標題') 建立標題更新後的新實體 未傳入任何參數的 copy
MDL-008 QuestionType 字串解析 'MULTIPLE_CHOICE' QuestionType.MULTIPLE_CHOICE 未知的字串退回預設值
MDL-009 AppUser 角色字串解析 'admin' UserRole.admin 無效的角色字串
MDL-010 AppUser.email getter 透過 Firebase user 初始化的 User 取得正確電子郵件字串 Firebase user 無電子郵件
MDL-011 UserRole 列舉排序 UserRole.admin > UserRole.guest 評估為 true 相同角色的比較
MDL-012 TransactionRecord.fromMap Map 的 timestamp 為毫秒 正確的 DateTime 物件 負數時間戳
MDL-013 TransactionRecord.toMap Transaction 物件 轉換為帶有毫秒時間戳的 Map
MDL-014 Comment.copyWith comment.copyWith(likes: 5) 更新後的評論
MDL-015 ExamMetadata 建構子 有效的參數 不可變的 ExamMetadata 物件

2. Services 測試 (約 30 個案例)

測試 ID 描述 輸入 預期輸出 邊界案例
SRV-001 SubnetValidator.ipToInt: 有效的 IPv4 '192.168.1.1' (IP 位址) 3232235777
SRV-002 SubnetValidator.ipToInt: 無效格式 '999.999.999.999' null 包含空白的字串
SRV-003 SubnetValidator.intToIp: 邊界值 0 '0.0.0.0' 超過最大 32 位元整數
SRV-004 WrongQuestionsService.add: 新增 新的題目 ID 加入清單,計數 = 1 ID 已存在
SRV-005 WrongQuestionsService.add: 現有 現有的 ID 計數遞增 最大整數限制
SRV-006 WrongQuestionsService.remove: 移除 現有的 ID 從清單中移除 ID 不存在
SRV-007 WrongQuestionsService.remove: 清理空值 考試的最後一個 ID 刪除考試鍵值
SRV-008 WrongQuestionsService.getKeys 錯題鍵值 Map 依時間戳降序排序 相同時間戳
SRV-009 WrongQuestionsService.getTodayCount 換日開始 0 時區變更
SRV-010 WrongQuestionsService.incrementToday increment() 計數 + 1
SRV-011 WrongQuestionsService.getGlobalCount 多個考試鍵值 所有錯題總和 空資料庫
SRV-012 TimeService.validateTime: 有效 NTP 時間與本機相符 true NTP 伺服器逾時
SRV-013 TimeService.validateTime: 小幅回滾 時間回滾 < 1 小時 true
SRV-014 TimeService.validateTime: 大幅回滾 時間回滾 > 1 天 false 時區切換
SRV-015 TtsService.speakAwait: 依序播放 3 段文字 按順序播放
SRV-016 TtsService.speakAwait: 逾時 長文播放 > 30 秒 觸發逾時例外
SRV-017 ApiKeyService: 來回加密 加密字串 原始字串 格式錯誤的負載
SRV-018 DeviceSecurityService: Web 平台 執行於 Web 傳回安全
SRV-019 DeviceSecurityService: 偵錯模式 執行於 Debug 傳回安全
SRV-020 AdkClientService (with GemmaLocalService offline fallback): auto 模式雲端 雲端連線正常 使用雲端 API
SRV-021 AdkClientService (with GemmaLocalService offline fallback): auto 模式降級 網路連線錯誤 使用本機模型 未下載本機模型
SRV-022 NetworkService: 連線偵測 Ping 成功 true 網頁驗證入口

3. Controllers 測試 (約 15 個案例)

測試 ID 描述 輸入 預期輸出 邊界案例
CTL-001 ExamController: admin 讀取 Admin 角色 傳回所有題目
CTL-002 ExamController: guest 讀取 Guest 角色 傳回 10 題已審核題目 題庫總數少於 10 題
CTL-003 ExamController: pending 讀取 Pending 角色 傳回所有已審核題目
CTL-004 ExamController: Repository 路由 切換至 MongoDB 狀態正確更新 無效的資料庫類型
CTL-005 ExamController: 廣告解鎖到期 檢查解鎖狀態 24 小時後傳回 false
CTL-006 MockExamController: 隨機選題 100 題的題庫 隨機抽出 50 題的子集 題庫總數不足
CTL-007 MockExamController: 計時器 120 分鐘 每秒遞減 應用程式進入背景
CTL-008 MockExamController: 分數計算 答對 40/50 題 分數 80.0 答題數為 0
CTL-009 MockExamController: 自動交卷 計時器歸 0 自動提交測驗

4. Repository 測試 (約 10 個案例)

測試 ID 描述 輸入 預期輸出 邊界案例
REP-001 RepositoryFactory: Mock 路由 設定 Mock 環境 傳回 MockExamRepo
REP-002 RepositoryFactory: powersync 設定 SQLite 提供者 傳回 PowerSyncRepo
REP-003 RepositoryFactory: mongodb 設定 MongoDB 提供者 傳回 MongoDbRepo
REP-004 RepositoryFactory: supabase 設定 Supabase 提供者 傳回 SupabaseRepo
REP-005 RepositoryFactory: 預設值 未設定提供者 傳回 FirebaseRepo
REP-006 RepositoryFactory: 切換 呼叫 updateDefaultProvider 後續呼叫傳回新提供者
REP-007 ExamRepository 介面 介面檢查 所有方法皆可實作

03-widget-tests.md

元件測試規範 (Widget Tests)

目標讀者:AI 代理與 QA 工程師。
背景:確保練習測驗應用程式中的各個 UI 元件能正確渲染並符合預期行為。

1. 元件測試 (約 20 個案例)

測試 ID 描述 預期渲染 預期互動
WID-001 QuestionOptionsWidget: 渲染單選題 視覺上顯示 A-D 選項。
WID-002 QuestionOptionsWidget: 點擊選項 被選取的選項顯示高亮。 點擊觸發 onSelect 回呼函式。
WID-003 QuestionOptionsWidget: 多選題 顯示核取方塊 (Checkbox) 而非單選按鈕。 點擊允許選取多個項目。
WID-004 QuestionOptionsWidget: 提交後高亮 正確答案顯示綠色,錯誤顯示紅色。
WID-005 QuestionOptionsWidget: 停用狀態 不透明度降低,視覺上呈現非作用中。 點擊沒有反應。
WID-006 QuestionView: 文字題目 Markdown 文字正確渲染。
WID-007 QuestionView: base64 圖片 圖片成功解碼並顯示。 點擊圖片展開全螢幕。
WID-008 QuestionView: 拖放題 渲染 Draggable 與 DragTarget 區域。 項目可拖放並吸附至目標。
WID-009 ExplanationView: markdown 解析 粗體、清單、程式碼區塊正確渲染。
WID-010 ExplanationView: 語言頁籤 顯示 EN/zh-TW 頁籤。 點擊切換顯示的詳解語言。
WID-011 AiTutorPanel: 聊天介面 渲染輸入框與訊息清單。
WID-012 AiTutorPanel: 傳送訊息 出現使用者對話泡泡。 提交按鈕觸發 AI 串流回應。
WID-013 AiTutorPanel: AI markdown 回應 AI 泡泡正確解析程式碼區塊。
WID-014 BannerAdWidget: 載入成功 廣告容器顯示內容。
WID-015 BannerAdWidget: 載入錯誤 元件自動摺疊或顯示佔位符號。
WID-016 SecurityWatermark: 渲染浮水印資訊 對角線顯示使用者 ID/Email。
WID-017 SecurityWatermark: 依角色調整不透明度 對未受信任的角色顯示較高不透明度。
WID-018 DiscussionWidget: 評論清單 渲染大頭貼、名稱、時間戳記。
WID-019 DiscussionWidget: 新增評論 顯示輸入框與傳送按鈕。 點擊傳送將新評論加入頂部。
WID-020 GlobalErrorBoundary: 錯誤捕獲 顯示通用錯誤畫面。 「重試」按鈕觸發回呼函式。

上一篇
search.feature , security.feature , tts-voice.feature , wrong-questions.feature
下一篇
test-spec : integration-tests , e2e-tests , test-matrix
系列文
將考國際證照的應用程式變成開源27
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言