关于 dart-testing
面向 Dart 包和 Flutter 应用的测试技能,介绍测试类型选择、依赖隔离、断言编写与命令行反馈流程。
主要功能
- 01单元、组件及集成测试指南
- 02按环境选择测试包
- 03使用 Mockito 隔离依赖
- 04测试命名、断言与异步匹配器
- 05运行及筛选测试命令
适用场景
- 01为 Dart 包或 Flutter 应用选择测试策略
- 02为含外部依赖的代码编写隔离测试
- 03按路径、标签或名称运行指定测试
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ dart-lang/ skills --skill dart-testing安装后在 Claude Code 中输入/dart-testing确认已加载。
详细介绍
测试 Dart 应用
目录
核心测试原则
根据目标环境和范围采用恰当的测试策略:
- 单元测试: 验证最小的可测试软件单元(函数、方法、类)。尽可能提高此处的覆盖率。
- 组件/Widget 测试: 验证组件(多个类或 Flutter Widget)的行为是否符合预期。使用模拟对象来模拟用户操作和事件。
- 集成/端到端测试: 在模拟/真实设备或浏览器上验证整个应用或大型子系统的行为。
测试环境的条件逻辑:
- 如果测试纯 Dart 包或服务端应用: 使用
package:test。 - 如果测试 Flutter 应用: 使用基于
package:test构建的flutter_test进行单元/Widget 测试,并使用integration_test或flutter_driver进行端到端测试。
测试实现指南
按照 test 包的惯例组织和编写测试。
- 描述性命名: 使用
group()对相关测试分类,并使用test()编写单个用例。提供清晰、描述性且能说明预期行为的名称。 - 断言: 始终使用
expect(actual, matcher)进行断言。 - 异步匹配器: 使用
completion()验证 Future 是否完成,使用throwsA()验证异常。 - 注解: 使用
@TestOn('browser')或@TestOn('vm')将测试限制在特定环境中。使用@Tag('name')为自定义配置中的测试分类。
模拟与隔离
隔离被测系统(SUT),确保执行快速且结果确定。
- 优先使用 Mock 和 Fake: 单元测试中不要进行真实网络调用、访问数据库或使用复杂的外部依赖。
- 使用
package:mockito: 为复杂依赖生成 Mock 类。定义固定场景,并验证 SUT 是否按预期与 Mock 对象交互。 - 代码生成: 使用
build_runner生成 Mock 实现(参见dart-code-generation)。
运行测试
使用命令行和有针对性的标志执行测试,以优化反馈周期。
- 运行所有测试:
dart test(或flutter test) - 运行指定目录中的测试:
dart test test/unit/或dart test test/integration/ - 运行指定文件中的测试:
dart test test/services/auth_test.dart - 按标签筛选:
dart test --tags="integration"或dart test --exclude-tags="slow" - 按名称筛选:
dart test --name="AuthService"
工作流
工作流:实现单元测试套件
实现新测试时,复制并跟踪此清单:
- 1. 确定要测试的类/函数及其外部依赖。
- 2. 在
test/目录中创建相应的_test.dart文件。 - 3. 使用
package:mockito或手动编写 Fake,为所有外部依赖定义 Mock 对象。 - 4. 使用描述性名称设置测试
group()。 - 5. 在
setUp()代码块中初始化 SUT 和 Mock。 - 6. 编写单个
test()用例,覆盖成功、失败和边界情况。 - 7. 使用
expect()和适当的匹配器(completion、throwsA等)。 - 8. 反馈循环: 运行
dart test path/to/test.dart-> 检查失败项 -> 修复实现或测试逻辑 -> 重复直至通过。
示例
高保真单元测试示例
import 'package:test/test.dart';
import 'package:mockito/mockito.dart';
import 'package:mockito/annotations.dart';
// Assume these are defined in your application code
import 'package:my_app/auth_service.dart';
import 'package:my_app/api_client.dart';
// Generate mocks using build_runner
@GenerateMocks([ApiClient])
import 'auth_service_test.mocks.dart';
void main() {
group('AuthService', () {
late AuthService authService;
late MockApiClient mockApiClient;
setUp(() {
mockApiClient = MockApiClient();
authService = AuthService(apiClient: mockApiClient);
});
test('login successfully returns a user token', () async {
// Arrange
when(mockApiClient.post('/login', any))
.thenAnswer((_) async => {'token': 'abc-123'});
// Act
final result = authService.login('user', 'password');
// Assert
await expectLater(result, completion(equals('abc-123')));
verify(mockApiClient.post('/login', any)).called(1);
});
test('login throws AuthException on invalid credentials', () async {
// Arrange
when(mockApiClient.post('/login', any))
.thenThrow(Exception('Unauthorized'));
// Act
final result = authService.login('user', 'wrong_password');
// Assert
await expectLater(result, throwsA(isA<AuthException>()));
});
});
}
相关技能
dart-static-analysis:用于配置可确保测试质量的 lint 规则。dart-code-generation:用于通过build_runner和mockito生成 Mock 对象。
评论
支持 Markdown