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

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

相关推荐
风华圆舞2 小时前
鸿蒙构建失败时,先查 Flutter 还是先查 Hvigor
flutter·华为·harmonyos
风华圆舞4 小时前
MethodChannel 在 Flutter 与 ArkTS 之间是怎么工作的
flutter·华为·harmonyos
恋猫de小郭4 小时前
Flutter 又为 AI 时代添砖加瓦:全新 ComponentLibrary 提议
android·前端·flutter
G_dou_5 小时前
Flutter三方库适配OpenHarmony【prime_checker】质数检测器项目完整实战
flutter·harmonyos
G_dou_5 小时前
Flutter三方库适配OpenHarmony【random_joke】随机笑话应用项目完整实战
flutter·harmonyos
MemoriKu5 小时前
Flutter 相册 APP 视频模态稳定化实战:从远端重构冲突到真机 Smoke Test
人工智能·python·flutter·机器学习·重构·音视频·新人首发
风华圆舞5 小时前
鸿蒙 Flutter 平台通道设计:为什么一项能力一个 channel
flutter·华为·harmonyos
BreezeDove5 小时前
【Android】Flutter命令超时无响应问题
android·flutter
G_dou_5 小时前
Flutter三方库适配OpenHarmony【quote_of_day】每日名言应用项目完整实战
flutter·harmonyos