Mockito 测试中模拟方法调用失败的常见原因与正确解决方案

老敏吖_2603

老敏吖_2603

2026-06-13

522人浏览

原创

Mockito 测试中模拟方法调用失败的常见原因与正确解决方案

本文详解 mockito 中使用 mock() 时为何 stubbed 方法在被真实逻辑调用时无效,并提供两种可靠方案:thencallrealmethod() 和 spy(),帮助开发者正确测试依赖内部方法调用的业务逻辑。

本文详解 mockito 中使用 mock() 时为何 stubbed 方法在被真实逻辑调用时无效,并提供两种可靠方案:thencallrealmethod() 和 spy(),帮助开发者正确测试依赖内部方法调用的业务逻辑。

在使用 Mockito 进行单元测试时,一个常见误区是:对 mock 对象的部分方法进行 stub(如 when(...).thenReturn(...)),却期望其未 stub 的其他方法(如 addUser)自动执行真实逻辑。实际上,Mockito.mock(Class) 创建的是一个完全空实现的对象——所有方法默认返回对应类型的默认值(如 boolean 返回 false,Object 返回 null),且不会执行原始类中的任何代码。

以你的测试为例:

@Test
public void AddExistingUser() {
    mockedManager = mock(UserManager.class);
    when(mockedManager.checkUsername("test")).thenReturn(true);

    assertThrows(IllegalArgumentException.class, () -> {
        mockedManager.addUser("test", "test"); // ❌ 不会执行真实 addUser 逻辑!
    });
}

问题在于:mockedManager.addUser(...) 是一个 stubbed 空方法,它根本不会进入你源码中 if (checkUsername(username)) { ... } 的判断分支,自然也不会触发异常。即使你 stub 了 checkUsername("test"),该 stub 也仅在显式调用该方法时生效;而 addUser 内部对 checkUsername 的调用,因 addUser 本身未被配置为调用真实逻辑,整个流程被 Mockito 拦截并静默返回默认值(void 方法无返回,但 checkUsername 在 addUser 内部调用时实际返回 false),导致条件不成立、异常未抛出。

✅ 正确做法有两种,按场景选择:

方案一:显式调用真实方法(推荐用于局部验证)

使用 thenCallRealMethod() 或 doCallRealMethod() 显式声明需执行真实逻辑的方法:

百度·度咔剪辑
百度·度咔剪辑

百度·度咔剪辑是一款由百度推出的创作 Agent 和 AI 视频剪辑工具。

下载
@Test
public void AddExistingUser() {
    mockedManager = mock(UserManager.class);
    // Stub 依赖方法
    when(mockedManager.checkUsername("test")).thenReturn(true);

    // 关键:让 addUser 调用真实实现
    doCallRealMethod().when(mockedManager).addUser("test", "test");

    assertThrows(IllegalArgumentException.class, () -> {
        mockedManager.addUser("test", "test"); // ✅ 执行真实 addUser,内部 checkUsername 返回 true
    });
}

⚠️ 注意:doCallRealMethod() 必须在 when(...).thenReturn(...) 之后调用,且 addUser 的参数需与 stub 保持一致(或使用 anyString() 等匹配器)。若 UserManager 构造依赖外部资源(如文件系统),建议在测试前通过 @BeforeEach 初始化其状态(如清空 usersData)。

方案二:使用 spy()(推荐用于集成度更高的行为测试)

spy() 基于真实对象创建“部分模拟”,默认执行所有方法的真实逻辑,仅对明确 stub 的方法进行覆盖:

@Test
public void AddExistingUser() {
    // 创建 spy:基于真实 UserManager 实例(需确保构造可执行)
    mockedManager = spy(new UserManager()); // ✅ 默认调用真实 addUser 和 checkUsername

    // 仅覆盖 checkUsername 行为(注意:spy 必须用 doReturn(...) 语法)
    doReturn(true).when(mockedManager).checkUsername("test");

    assertThrows(IllegalArgumentException.class, () -> {
        mockedManager.addUser("test", "test"); // ✅ 真实 addUser 执行,内部调用 stubbed checkUsername
    });
}

? 提示:spy() 要求目标类有可访问的构造函数(通常为 public 无参构造),且需用 doReturn(...).when(spy).method() 替代 when(...).thenReturn(...),否则可能触发真实方法执行(引发副作用)。

总结

  • mock() → 全空对象,所有方法默认不执行逻辑,必须显式配置 thenCallRealMethod() 才能触发真实行为;
  • spy() → 真实对象代理,默认执行真实逻辑,仅对 doReturn() 等明确 stub 的方法进行拦截;
  • 优先使用 spy() 测试含内部方法调用的业务逻辑;若需彻底隔离依赖(如避免文件 I/O),则应在 spy 前注入可控的依赖(如 mock file 字段)或改用 mock() + thenCallRealMethod() + 细粒度 stub。

掌握这两者的本质区别,可从根本上避免“stub 生效但测试失败”的陷阱。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
软件测试常用工具
软件测试常用工具

软件测试常用工具有Selenium、JUnit、Appium、JMeter、LoadRunner、Postman、TestNG、LoadUI、SoapUI、Cucumber和Robot Framework等等。测试人员可以根据具体的测试需求和技术栈选择适合的工具,提高测试效率和准确性 。

2023.10.13

4350

8

java测试工具有哪些
java测试工具有哪些

java测试工具有JUnit、TestNG、Mockito、Selenium、Apache JMeter和Cucumber。php还给大家带来了java有关的教程,欢迎大家前来学习阅读,希望对大家能有所帮助。

2023.10.23

2741

10

Java 单元测试
Java 单元测试

本专题聚焦 Java 在软件测试与持续集成流程中的实战应用,系统讲解 JUnit 单元测试框架、Mock 数据、集成测试、代码覆盖率分析、Maven 测试配置、CI/CD 流水线搭建(Jenkins、GitHub Actions)等关键内容。通过实战案例(如企业级项目自动化测试、持续交付流程搭建),帮助学习者掌握 Java 项目质量保障与自动化交付的完整体系。

2025.10.24

1026

26

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

2026.09.30

120

10

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

2026.09.30

100

14

LLVM IR中间表示入门指南
LLVM IR中间表示入门指南

本专题整理LLVM IR的核心概念,包括中间表示作用、模块结构、函数、基本块、SSA形式、类型系统和常见语法,帮助新手理解LLVM编译流程中的关键层。

2026.09.30

80

12

PDF转图片方法
PDF转图片方法

需要把 PDF 页面用于上传、预览、分享或图片归档时,PDF 转图片方法专题整理 JPG/PNG 格式选择、逐页导出、清晰度设置、批量下载和结果检查等流程,帮助用户稳定完成 PDF 图片化处理。

2026.09.30

60

26

PixTV AI视频生成与无限画布创作
PixTV AI视频生成与无限画布创作

PixTV专题整理AI视频与视觉内容创作相关功能使用教程,涵盖AI生图、视频生成、无限画布、多模型创作、素材管理、声音音乐及视频剪辑等功能,帮助用户快速掌握PixTV从创意到成片的完整制作方法。

2026.09.29

80

15

Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

2026.09.23

280

15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习