測試 Dart 和 Flutter 應用程式
目錄
組織測試檔案
將測試檔案依照 lib 目錄結構進行組織,以保持可預測性。
- 將所有測試程式碼放置在套件根目錄下的
test目錄中。 - 在測試檔案名稱的結尾加上
_test.dart(例如:lib/src/utils.dart應在test/src/utils_test.dart中進行測試)。 - 如果要撰寫整合測試,請將它們放置在套件根目錄下的
integration_test目錄中。
撰寫測試
使用 package:test 作為 Dart 應用程式的標準測試函式庫。
- 匯入
package:test/test.dart(若為 Flutter 則匯入package:flutter_test/flutter_test.dart)。 - 使用
group()函式將相關測試分組,以提供共用上下文。 - 使用
test()函式定義個別的測試案例。 - 使用
expect()函式搭配匹配器(例如equals()、isTrue、throwsA())驗證結果。 - 使用標準的
async/await語法撰寫非同步測試。測試執行器會自動等待Future完成。 - 使用
setUp()和tearDown()回呼管理測試的設定與清理。 - 若測試的程式碼依賴依賴注入,請使用
package:mockito搭配package:test產生 mock 物件、配置固定情境,並驗證互動行為。
執行測試
根據專案類型和測試位置選擇適當的測試執行器。
- 如果是純 Dart 專案,使用
dart test指令執行測試。 - 如果是 Flutter 專案,使用
flutter test指令執行測試。 - 如果要執行整合測試,請明確指定目錄路徑,因為預設執行器會忽略它:
dart test integration_test或flutter test integration_test。
測試實作工作流程
在實作新的測試套件時,請遵循以下順序工作流程。複製核對清單以追蹤您的進度。
任務進度
- 1. 在
test/目錄中建立測試檔案,確保使用_test.dart後綴。 - 2. 匯入
package:test/test.dart和目標函式庫。 - 3. 定義
main()函式。 - 4. 使用
setUp()初始化共用資源或 mock。 - 5. 使用
test()撰寫按功能分組的測試案例,並搭配group()。 - 6. 使用適當的 CLI 指令執行測試套件。
- 7. 反饋迴圈:執行測試 → 檢視堆疊追蹤以找出失敗原因 → 修正實作或斷言 → 重新執行直到通過。
範例
標準單元測試套件
示範分組、設定、同步和非同步測試。
import 'package:test/test.dart';
import 'package:my_package/calculator.dart';
void main() {
group('Calculator', () {
late Calculator calc;
setUp(() {
calc = Calculator();
});
test('正確地將兩個數字相加', () {
expect(calc.add(2, 3), equals(5));
});
test('處理非同步操作', () 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('在 API 呼叫成功時回傳解析後的資料', () async {
// 配置 mock
when(mockApiClient.get('/data')).thenAnswer((_) async => '{"id": 1}');
// 執行受測系統
final result = await dataService.fetchData();
// 驗證結果和互動行為
expect(result.id, equals(1));
verify(mockApiClient.get('/data')).called(1);
});
});
}