mcpField
D
dart-testing

dart-testing

github.com/dart-lang测试与质量53267 次安装2 周前更新
代码仓库

关于 dart-testing

面向 Dart 包和 Flutter 应用的测试技能,介绍测试类型选择、依赖隔离、断言编写与命令行反馈流程。

主要功能

  1. 01单元、组件及集成测试指南
  2. 02按环境选择测试包
  3. 03使用 Mockito 隔离依赖
  4. 04测试命名、断言与异步匹配器
  5. 05运行及筛选测试命令

适用场景

  1. 01为 Dart 包或 Flutter 应用选择测试策略
  2. 02为含外部依赖的代码编写隔离测试
  3. 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