3.1 严格Stubbing模式

devtools/2025/2/15 21:42:09/

严格Stubbing(Strict Stubbing)是Mockito提供的一种增强测试严谨性的模式,旨在检测以下问题:

  • 多余的Stubbing:配置了未被调用的方法桩。
  • 不必要的Stubbing:Stubbing未被使用且不影响测试结果。
  • 桩顺序错误:Stubbing被覆盖或错误使用。

通过严格模式,可以避免测试代码中的“虚假通过”(False Positive),确保每个Stubbing都有明确的目的。


1. 启用严格Stubbing

Mockito提供了两种方式启用严格模式:

1.1 全局启用(推荐)

在测试类上添加 @MockitoSettings(strictness = Strictness.STRICT_STUBS)

java">@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS) // 全局启用严格模式
public class OrderServiceTest {// 测试代码...
}
1.2 手动启用

通过 MockitoSession 在单个测试中启用:

java">@Test
void testWithManualStrictness() {try (MockitoSession session = Mockito.mockitoSession().strictness(Strictness.STRICT_STUBS).startMocking()) {// 测试代码...}
}

2. 严格模式下的错误场景与示例
2.1 多余的Stubbing

问题:配置了未被调用的Stubbing。
示例

java">@Mock
private UserDao mockUserDao;@Test
void findUser_ShouldReturnUser() {// 多余的Stubbing:findByEmail未被调用when(mockUserDao.findByUsername("alice")).thenReturn(new User());when(mockUserDao.findById(1)).thenReturn(new User()); // 实际被调用的StubbingUser user = userService.findUserById(1); // 调用findById(1)verify(mockUserDao).findById(1);
}

错误信息

Unnecessary stubbings detected.
2.2 不必要的Stubbing

问题:Stubbing存在但未被使用,且不影响测试结果。
示例

java">@Test
void createUser_ShouldNotDependOnFindMethod() {when(mockUserDao.findByUsername("alice")).thenReturn(null); // 未被使用doNothing().when(mockUserDao).save(any());userService.createUser("alice", "pass123");verify(mockUserDao).save(any());
}

错误信息:同上,提示存在不必要的Stubbing。


3. 解决方案
3.1 删除多余的Stubbing

直接移除未被调用的桩代码:

java">@Test
void findUser_ShouldReturnUser() {// 删除多余的findByUsername桩when(mockUserDao.findById(1)).thenReturn(new User());User user = userService.findUserById(1);verify(mockUserDao).findById(1);
}
3.2 显式标记宽松Stubbing

使用 lenient() 忽略特定Stubbing的检测:

java">@Test
void createUser_ShouldAllowUnusedStubbing() {// 标记为宽松Stubbinglenient().when(mockUserDao.findByUsername("alice")).thenReturn(null);doNothing().when(mockUserDao).save(any());userService.createUser("alice", "pass123");verify(mockUserDao).save(any());
}

4. 严格模式的进阶用法
4.1 验证Stubbing顺序

严格模式会检测Stubbing的覆盖顺序。例如,重复定义同一方法的Stubbing可能导致意外覆盖:

java">@Test
void testStubbingOrder() {when(mockList.get(0)).thenReturn("A");when(mockList.get(0)).thenReturn("B"); // 覆盖前一个StubbingassertEquals("B", mockList.get(0)); // 通过
}

严格模式下会提示 PotentialStubbingProblem,建议使用 doReturn() 链式配置:

java">when(mockList.get(0)).thenReturn("A").thenReturn("B");
4.2 检测无效的Stubbing参数

严格模式会检查参数匹配器的使用是否正确:

java">@Test
void testInvalidMatcher() {// 错误:混合精确值和匹配器when(mockUserDao.find(eq("alice"), anyString())).thenReturn(null);
}

错误信息

Invalid use of argument matchers!

5. 最佳实践
  • 仅Mock必要的交互:避免过度Mock,仅覆盖影响当前测试的依赖方法。
  • 及时清理无用桩代码:定期运行测试并修复严格模式提示的问题。
  • 合理使用 lenient():仅在明确需要时放宽检测,如共享测试配置中的通用桩。
  • 结合日志分析:通过 Mockito.mockingDetails(mock).printInvocations() 调试Stubbing调用。

总结

严格Stubbing模式通过强制检测冗余和无效的桩代码,显著提升单元测试的健壮性和可维护性。结合示例中的修复策略,开发者可以快速定位问题并优化测试逻辑,确保每个Stubbing都精准服务于测试目标。


http://www.ppmy.cn/devtools/159155.html

相关文章

游戏APP如何通过精准广告策略实现广告变现收益增长?

不同类型的游戏APP合作AdSet聚合广告平台,量身定制广告变现方案,以提升变现收益的表现。#app广告变现 1、智能选择广告形式 基于用户的行为习惯,推荐优化广告格式,包括插屏广告、激励视频广告和Banner广告等,最大化广…

【javascript】录音可视化

文章目录 前言一、音频数据格式1. 常见的数据格式 二、获取音频方式1. 用FileReader对象读取音频文件2. 通过url请求获取音频数据3. 录音获取音频流 三、音频格式转换四、音频可视化总结 前言 分享一些在开发语音识别功能遇到的问题和解决方法,包含音频数据格式转换…

Linux入侵检查流程

1. 初步信息收集 1.1 系统信息 • 目的:了解当前系统的基本情况,包括操作系统版本、内核版本等。 • 命令: # 查看操作系统发行版信息 cat /etc/os-release # 查看内核版本 uname -r 1.2 网络信息 • 目的:查看网络连接状态、…

【LeetCode: 1552. 两球之间的磁力 + 二分】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…

QT笔记——QRadioButton

文章目录 1、概要2、实际的应用2.1、创建多个QRadioButton,只可同时选中其中一个,点击后实现对应的槽函数 1、概要 实现QRadioButton相关的应用;2、实际的应用 2.1、创建多个QRadioButton,只可同时选中其中一个,点击后实现对应的槽函数 创建…

Android:播放Rtsp视频流的两种方式

一.SurfaceView Mediaplayer XML中添加SurfaceView: <SurfaceViewandroid:id"id/surface_view"android:layout_width"match_parent"android:layout_height"match_parent"/> Activity代码&#xff1a; package com.android.rtsp;impor…

【第4章:循环神经网络(RNN)与长短时记忆网络(LSTM)— 4.5 序列标注与命名实体识别】

一、引言 嘿,各位技术小伙伴们!今天咱们要来深入聊聊循环神经网络(RNN)和长短时记忆网络(LSTM),这俩在序列标注和命名实体识别领域那可是相当厉害的角色。咱就从最基础的概念开始,一步步揭开它们神秘的面纱,看看它们到底是怎么在实际应用中发挥巨大作用的。 二、序列…

ES常用查询

根据编号查询 GET custom/_search { "query": { "term": { "no": "abc" } } } 查询指定的列 GET custom/_search { "_source": ["id", "no"], "size": 10000, …