mcpField
M
mocktail

mocktail

github.com/evanca测试与质量663192 次安装3 周前更新
代码仓库

关于 mocktail

面向 Dart 和 Flutter 测试开发者的 mocktail 使用指南,介绍无需代码生成创建测试替身的方法。内容涵盖回退值注册、存根设置、参数匹配和交互验证。

主要功能

  1. 01选择真实对象、Fake 或 Mock
  2. 02无需代码生成创建 Mock
  3. 03注册自定义回退值
  4. 04设置方法与异步调用存根
  5. 05验证并捕获交互

适用场景

  1. 01为 Dart 服务创建测试替身
  2. 02在测试中匹配命名参数
  3. 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