`mockito` 的核心“打桩”规则

掌握 mockito 中不同的"打桩 (Stubbing)"技巧,是写出高质量单元测试的关键。

when(...).thenAnswer(...) 只是其中一种方式,实际上 mockito 提供了一套非常灵活的 API 来规定 Mock 对象在被调用时的行为。

总结一下最常用、最重要的几种规则:


mockito 的核心"打桩"规则

假设我们有一个 mockRepository,它有一个方法 String? findUser(int id)

1. thenReturn - 返回一个具体的值

这是最常用、最简单的规则。它规定当方法被调用时,直接返回一个预设好的值。

使用场景 :当方法的返回值是一个可以直接创建的、简单的对象时(如 String, int, bool,或者一个你自己创建的模型实例)。

代码示例

dart 复制代码
// 规定:当 findUser 被以参数 1 调用时,返回字符串 '张三'
when(mockRepository.findUser(1)).thenReturn('张三');

// 规定:当 findUser 被以任何整数参数调用时,返回字符串 '默认用户'
// an_y 是 mockito 提供的匹配器,表示"任何值"
when(mockRepository.findUser(any)).thenReturn('默认用户');

// 规定:当一个返回 Future 的方法被调用时,返回一个已完成的 Future
when(mockRepository.syncFromRemote()).thenReturn(Future.value()); 

2. thenThrow - 抛出一个异常

用于测试代码中的错误处理逻辑。

使用场景:模拟网络请求失败、数据库读取错误、文件未找到等异常情况。

代码示例

dart 复制代码
// 规定:当 findUser 被以参数 -1 调用时,抛出一个 Exception
when(mockRepository.findUser(-1)).thenThrow(Exception('用户ID无效'));

// 测试代码就可以这样写:
expect(
  () => userManager.getUserName(-1), 
  throwsException
);

3. thenAnswer - 执行一个函数并返回其结果

这是最强大、最灵活 的规则。它允许你提供一个函数,当 Mock 方法被调用时,mockito 会执行你提供的这个函数,并将函数的返回值作为 Mock 方法的返回值。

使用场景

  • 当返回值是一个 FutureStream 时(这是最常见的用法)。
  • 当返回值需要根据传入的参数动态计算时。
  • 当您想在方法被调用时执行一些额外的逻辑(比如打印日志)。

代码示例

dart 复制代码
// 规定:当 syncFromRemote 被调用时,执行一个异步函数,并返回一个空的 Future
// 这是您问题中的例子,非常适合异步方法
when(mockRepository.syncFromRemote()).thenAnswer((_) async => {});

// 规定:当 findUser 被调用时,根据传入的 id 动态返回一个名字
when(mockRepository.findUser(any)).thenAnswer((invocation) {
  // invocation 对象包含了调用的所有信息,包括参数
  final int id = invocation.positionalArguments.first;
  return '用户 $id';
});

// 使用
print(mockRepository.findUser(101)); // 会输出: '用户 101'

4. thenCallRealMethod - 调用真实的原始方法

使用场景 :这在使用 spy 时非常有用。spy 是一种特殊的 Mock 对象,它会"包装"一个真实的对象。默认情况下,调用 spy 的方法会执行真实的方法,但您可以用 when 来覆盖其中某几个方法的行为。thenCallRealMethod 可以让被覆盖的方法恢复其原始的真实行为。

代码示例

dart 复制代码
// 1. 创建一个真实的对象和一个 spy
final realRepo = RealRepository();
final spyRepo = spy(realRepo);

// 2. 默认情况下,spy 会调用真实方法
spyRepo.someMethod(); // 执行 RealRepository.someMethod()

// 3. 我们可以覆盖某个方法的行为
when(spyRepo.someMethod()).thenReturn('假的返回值');
spyRepo.someMethod(); // 返回 '假的返回值'

// 4. 现在,我们可以让它恢复真实的行为
when(spyRepo.someMethod()).thenCallRealMethod();
spyRepo.someMethod(); // 再次执行 RealRepository.someMethod()

总结

规则 作用 最常用场景
thenReturn(value) 直接返回一个预设的值 同步方法,返回简单对象
thenThrow(error) 直接抛出一个预设的异常 测试错误处理和异常流程
thenAnswer(function) 执行一个函数并返回其结果 异步方法 (Future),或需要根据参数动态返回值的场景
thenCallRealMethod() 调用被包装的真实方法 spy 配合使用,用于临时恢复真实行为

掌握这四种核心的"打桩"规则,您就能够非常自如地为几乎所有场景编写出简洁、健壮的单元测试了。

相关推荐
Bryce李小白1 天前
Flutter 自定义 View 权威指引
flutter
恋猫de小郭1 天前
Fluttercon EU 2025 :Let‘s go far with Flutter
android·开发语言·flutter·ios·golang
SoaringHeart3 天前
Flutter进阶:自定义一个 json 转 model 工具
前端·flutter·dart
许泽宇的技术分享3 天前
Flutter + Ollama:开启本地AI的全平台新纪元 —— 从零剖析一款现代化AI客户端的技术奥秘
人工智能·flutter
molihuan3 天前
开源 全平台 哔哩哔哩缓存视频合并 Github地址:https://github.com/molihuan/hlbmerge_flutter
android·flutter·缓存·ffmpeg·开源·github·音视频
dora3 天前
Flutter中dart和原生代码的通信之MethodChannel
android·flutter
brave7234 天前
Riverpod 3.0.0 版本中 Provider 类型选择指南
flutter
ZFJ_张福杰4 天前
【区块链】Fiat24 深度解读(含 Flutter 集成与 SDK 骨架)
flutter·web3·区块链·钱包
古希腊被code拿捏的神4 天前
【Flutter】抽象类的运用(abstract与implements的实践)
flutter
ZFJ_张福杰4 天前
【Flutter】GetX最佳实践与避坑指南
android·flutter·ios·getx