关于 flutter-testing
面向 Flutter 开发者的测试策略技能,规定覆盖率、组织方式、独立性和命名的实践,并介绍适用于单元、组件和集成测试的黄金图变体、状态矩阵及交互契约模式。
主要功能
- 01测试金字塔与覆盖率指导
- 02测试文件镜像式组织
- 03独立测试规范
- 04黄金图变体测试模式
- 05状态矩阵与交互契约模式
适用场景
- 01测试设计系统组件的视觉变体
- 02检查有状态组件的全部状态
- 03验证可复用组件的交互规则
- 04运行单元、组件或集成测试
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ dhruvanbhalara/ skills --skill flutter-testing安装后在 Claude Code 中输入/flutter-testing确认已加载。
详细介绍
测试策略
- 测试金字塔:更多单元测试和组件测试,更少集成测试。单元测试速度最快、成本最低。
- 镜像测试规则:逻辑和组件覆盖率达到 100%。所有代码都必须有测试。
- 镜像组织结构:测试文件必须严格镜像
lib/目录结构,并以_test.dart结尾。 - 覆盖率目标:
domain和bloc层的逻辑覆盖率目标为 100%。 - 测试独立性:每个测试必须相互独立。测试之间不得共享可变状态。
测试类型概览
| 类型 | 范围 | 速度 | 技能 |
|---|---|---|---|
| 单元测试 | 单个函数/类 | 快 | dart-testing |
| 组件测试 | 单个 UI 组件 | 中 | flutter-add-widget-test |
| 集成测试 | 完整应用 / 用户流程 | 慢 | flutter-add-integration-test |
基于模式的测试
以下三种模式可以减少重复的测试设置、覆盖所有视觉状态,并确保组件行为一致。它们是约定,而非软件包。
Golden 变体测试
当组件有多种视觉状态(主要、禁用、悬停、错误)时,应在一个结构化的 group() 中使用 Map<String, Widget Function()> 测试所有变体:
- 定义一个
variants映射,其中键为状态名称,值为组件构建器。 - 每个变体都必须单独渲染(每个变体调用一次全新的
pumpWidget)。 - 使用确定性的 Golden 文件命名:
goldens/<component>.<variant>.png。 - 通过
tester.view.physicalSize设置一致的surfaceSize,避免像素差异测试出现不稳定结果。 - 适用场景:设计系统组件、具有不同模式/类型的组件。
- 不适用场景:集成测试或动画帧验证。
状态矩阵测试
每个有状态组件都必须针对所有可能的 UI 状态进行测试。使用状态矩阵将设置与验证分开:
- 定义一个
states映射,包含组件可以呈现的每种状态(loading、error、data、empty)。 - 编写一个
verify(stateName)回调,使用switch表达式断言每种状态下的正确渲染结果。 - 此模式可以避免只测试“正常路径”这一常见错误。
- 适用场景:具有复杂状态机的组件(例如由 BLoC 驱动的屏幕)。
- 不适用场景:如果不同状态的验证逻辑差异很大,应编写单独的测试。
交互契约测试
可复用组件有隐含的行为规则。应将这些规则定义为明确且可复用的契约:
- 在
test/utils/中为常见契约创建辅助函数:verifyTappable(tester, finder, mockCallback):点击会准确触发一次回调。verifyDisabledNotTappable(tester, finder, mockCallback):禁用时点击不会触发回调。verifyValidatesOnBlur(tester, finder):焦点离开时触发验证。
- 在所有行为相同的组件中一致地应用这些契约。
- 适用场景:行为规则严格明确,且重构后仍必须成立的组件。
- 不适用场景:仅某个组件独有的一次性逻辑。
测试命名与结构
- 测试命名:使用字符串插值作为测试组名称:
group('$ClassName',,而不是group('ClassName',。这可确保一致性,并提供更好的工具支持。 - 测试分组:使用
group()按功能、类或状态组织测试,以便更清晰地查看报告。 - 描述性名称:测试名称应清楚说明测试内容及原因。
常见测试错误
A RenderFlex overflowed...:在测试中用Expanded包裹组件,或限制其尺寸Vertical viewport was given unbounded height:在测试中用具有固定高度的SizedBox包裹ListViewsetState called during build:将状态更改延迟到帧后回调中No MediaQuery widget ancestor:始终用MaterialApp包裹测试组件
运行测试(快速参考)
flutter test:运行所有单元测试和组件测试flutter test test/path/to/file_test.dart:运行指定的测试文件flutter test integration_test/:运行集成测试flutter test --coverage:运行测试并生成覆盖率报告dart test:运行纯 Dart 单元测试
评论
支持 Markdown