`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 配合使用,用于临时恢复真实行为

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

相关推荐
恋猫de小郭1 天前
Amper 正式转正 Kotlin Toolchain ,Gradle 未来何去何从
android·前端·flutter
张风捷特烈1 天前
Flutter 类库大揭秘#02 | path_provider 各平台实现
前端·flutter
TT_Close2 天前
别劝退了!5秒搞定 Flutter 鸿蒙 FVM 起跑线
flutter·harmonyos·visual studio code
你听得到112 天前
用户说 App 卡,但说不清在哪?我把 Flutter 监控 SDK 升级成了链路观测工作台
前端·flutter·性能优化
stringwu4 天前
Flutter 开发必备:MVI 架构的高效实现指南
前端·flutter
程序员老刘5 天前
Flutter版本选择指南:3.44系列继续观望 | 2026年6月
flutter·ai编程·客户端
用户965597361906 天前
Provider vs Bloc vs GetX vs Riverpod:Flutter 状态管理方案怎么选?
flutter
恋猫de小郭6 天前
Flutter Patchwork,不用 Fork 改依赖包源码的第三方工具
android·前端·flutter
程序员老刘7 天前
跑分第一的编程大模型,我为啥不用?
flutter·ai编程·vibecoding
恋猫de小郭7 天前
苹果 AirPods 协议,Android 也可以使用完整版 AirPods 能力
android·前端·flutter