SKILL.md
唯讀
名稱
dart-add-unit-test
描述
使用 `package:test` 為函式、方法與類別撰寫並整理單元測試。適合在開發新邏輯或修復 Bug 時使用,確保程式碼正確無誤且防止發生回歸錯誤(regression)。
Dart 與 Flutter 應用程式測試
目錄
規劃測試檔案結構
妥善組織測試檔案,使其對齊 lib 目錄結構,以保持專案架構的可預測性。
- 將所有測試程式碼放置於 Package 根目錄下的
test目錄中。 - 所有測試檔案名稱末尾皆需加上
_test.dart(例如lib/src/utils.dart的測試檔案應為test/src/utils_test.dart)。 - 若要撰寫整合測試,請放置於 Package 根目錄下的
integration_test目錄中。
撰寫測試
使用 package:test 作為 Dart 應用程式的標準測試函式庫。
- 匯入
package:test/test.dart(若為 Flutter 專案,則匯入package:flutter_test/flutter_test.dart)。 - 使用
group()函式將相關測試分組,以提供共享的情境上下文。 - 使用
test()函式定義獨立的測試案例。 - 搭配 Matcher(例如
equals()、isTrue、throwsA())使用expect()函式驗證執行結果。 - 使用標準的
async/await語法撰寫非同步測試,Test runner 會自動等待Future執行完成。 - 使用
setUp()與tearDown()回調(callbacks)管理測試前後的環境設定與資源清理。 - 若被測試的程式碼依賴依賴注入(Dependency Injection),可結合
package:mockito與package:test來產生 Mock 物件、設定預期情境並驗證互動行為。
執行測試
根據專案類型與測試檔案所在位置,選擇合適的 Test runner。
- 若為純 Dart 專案,請使用
dart test命令執行測試。 - 若為 Flutter 專案,請使用
flutter test命令執行測試。 - 若要執行整合測試,由於預設 runner 會忽略該目錄,因此需明確指定路徑:
dart test integration_test或flutter test integration_test。
測試實作工作流程
實作新的測試套件時,請遵循以下步驟流程。可以複製這份檢查清單來追蹤進度。
任務進度
- [ ] 1. 在
test/目錄中建立測試檔案,並確認副檔名包含_test.dart。 - [ ] 2. 匯入
package:test/test.dart以及目標函式庫。 - [ ] 3. 定義
main()函式。 - [ ] 4. 使用
setUp()初始化共享資源或 Mock 物件。 - [ ] 5. 使用
group()依功能將test()案例分組撰寫。 - [ ] 6. 使用相應的 CLI 命令執行測試套件。
- [ ] 7. 回饋循環(Feedback Loop):執行測試 -> 檢視失敗的 Stack trace -> 修復實作程式碼或斷言(assertions)-> 重新執行直到全部通過。
範例
標準單元測試套件
展示測試分組、環境設定、同步與非同步測試的撰寫方式。
import 'package:test/test.dart';
import 'package:my_package/calculator.dart';
void main() {
group('Calculator', () {
late Calculator calc;
setUp(() {
calc = Calculator();
});
test('adds two numbers correctly', () {
expect(calc.add(2, 3), equals(5));
});
test('handles asynchronous operations', () async {
final result = await calc.fetchRemoteValue();
expect(result, isNotNull);
expect(result, greaterThan(0));
});
});
}
使用 Mockito 進行 Mock 測試
展示如何設定 Mock 物件以進行依賴注入測試。
import 'package:test/test.dart';
import 'package:mockito/mockito.dart';
import 'package:mockito/annotations.dart';
import 'package:my_package/api_client.dart';
import 'package:my_package/data_service.dart';
// 使用 build_runner 產生 Mock:dart run build_runner build
@GenerateNiceMocks([MockSpec<ApiClient>()])
import 'data_service_test.mocks.dart';
void main() {
group('DataService', () {
late MockApiClient mockApiClient;
late DataService dataService;
setUp(() {
mockApiClient = MockApiClient();
dataService = DataService(apiClient: mockApiClient);
});
test('returns parsed data on successful API call', () async {
// 設定 Mock 物件的預期行為
when(mockApiClient.get('/data')).thenAnswer((_) async => '{"id": 1}');
// 執行被測試系統(System Under Test)
final result = await dataService.fetchData();
// 驗證結果與互動行為
expect(result.id, equals(1));
verify(mockApiClient.get('/data')).called(1);
});
});
}






