关于 mocktail
面向 Dart 和 Flutter 测试开发者的 mocktail 使用指南,介绍无需代码生成创建测试替身的方法。内容涵盖回退值注册、存根设置、参数匹配和交互验证。
主要功能
- 01选择真实对象、Fake 或 Mock
- 02无需代码生成创建 Mock
- 03注册自定义回退值
- 04设置方法与异步调用存根
- 05验证并捕获交互
适用场景
- 01为 Dart 服务创建测试替身
- 02在测试中匹配命名参数
- 03检查调用并捕获参数
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ evanca/ flutter-ai-rules --skill mocktail安装后在 Claude Code 中输入/mocktail确认已加载。
详细介绍
Mocktail 技能
本技能定义了如何在 Dart 和 Flutter 测试中正确使用 mocktail 包进行模拟。
1. Mock、Fake 与真实对象
| 用途 | 适用场景 |
|---|---|
| 真实对象 | 实际可行时,优先使用真实对象,而不是 Mock。 |
Fake(extends Fake) | 轻量级自定义实现;只重写所需的方法。如果不需要验证交互,优先于 Mock。 |
Mock(extends Mock) | 仅在需要验证交互(调用次数、参数)或为动态响应设置桩时使用。 |
- 绝不要向继承
Mock的类添加@override方法或实现。 - 只有在测试中包含
verify断言时才使用 Mock;否则优先使用真实对象或 Fake。
2. 创建 Mock
class MockMyService extends Mock implements MyService {}
class FakeMyEvent extends Fake implements MyEvent {}
无需代码生成——与 Mockito 不同,Mocktail 会在运行时使用 noSuchMethod。
3. 注册回退值
在使用自定义类型和参数匹配器之前,先注册回退值。在 setUpAll 中或测试开头执行:
setUpAll(() {
registerFallbackValue(FakeMyEvent());
});
- 使用
any()、captureAny()或captureThat()匹配非空自定义类型时,必须注册回退值。 - 为参数匹配器使用的所有自定义类型注册回退值。
4. 设置桩
final mock = MockMyService();
// Return a value
when(() => mock.fetchData()).thenReturn('result');
// Throw an error
when(() => mock.fetchData()).thenThrow(Exception('error'));
// Dynamic/async response
when(() => mock.fetchData()).thenAnswer((_) async => 'result');
// Future<void>
when(() => mock.doWork()).thenAnswer((_) async {});
- 始终使用
thenAnswer为异步方法(返回Future或Future<void>)设置桩。 - 为预期会被调用的每个方法设置桩,即使该方法不是测试的重点。
5. 命名参数
在 when 和 verify 调用中始终包含所有命名参数。对于不关心的参数,使用 any(named: 'paramName'):
when(() => mock.fetch(
id: any(named: 'id'),
headers: any(named: 'headers'),
)).thenReturn(response);
- 如果方法的命名参数有默认值,Mocktail 仍要求匹配所有这些参数。
6. 验证
verify(() => mock.fetchData()); // called at least once
verifyNever(() => mock.fetchData()); // never called
verify(() => mock.fetchData()).called(2); // called exactly twice
7. 参数匹配器
// Any positional argument
when(() => mock.process(any())).thenReturn(true);
// Capture arguments for later assertions
final captured = verify(() => mock.process(captureAny())).captured;
print(captured.last);
- 对于不关心具体值的位置参数,使用
any()。 - 使用
captureThat()进行条件捕获。 - 匹配字符串输出时,请留意该类型的
.toString()会返回什么。
参考资料
评论
支持 Markdown