2.7 静态方法/构造函数Mock

静态方法/构造函数Mock

在单元测试中,静态方法构造函数的Mock是相对复杂的需求,因为Mockito的核心设计基于对象实例的模拟。然而,通过扩展工具或特定技巧,可以实现对这些场景的处理。本章详解两种主流方案:PowerMock(传统方案)和Mockito-Inline(现代方案)。


1. 为什么需要Mock静态方法/构造函数?
  • 遗留代码:旧代码中广泛使用静态工具类(如DateUtils.format())。
  • 第三方库依赖:如调用System.currentTimeMillis(),需固定返回值。
  • 不可控对象创建:需要拦截构造函数,返回Mock实例(如单例类)。

2. 方案一:使用PowerMock(传统方案)

PowerMock 是Mockito的扩展,支持静态方法、构造函数、私有方法等的Mock,但需复杂配置且与现代框架兼容性有限。

2.1 环境配置
<!-- pom.xml 添加依赖 -->
<dependency><groupId>org.powermock</groupId><artifactId>powermock-module-junit4</artifactId><version>2.0.9</version><scope>test</scope>
</dependency>
<dependency><groupId>org.powermock</groupId><artifactId>powermock-api-mockito2</artifactId><version>2.0.9</version><scope>test</scope>
</dependency>
2.2 Mock静态方法
@RunWith(PowerMockRunner.class)
@PrepareForTest({StringUtils.class}) // 声明待Mock的类
public class PowerMockTest {@Testpublic void mockStaticMethod() {// 1. 准备静态类PowerMockito.mockStatic(StringUtils.class);// 2. 配置静态方法行为PowerMockito.when(StringUtils.isEmpty(anyString())).thenReturn(false);// 3. 执行测试逻辑boolean result = StringUtils.isEmpty("test"); // 返回falseassertFalse(result);}
}
2.3 Mock构造函数
@RunWith(PowerMockRunner.class)
@PrepareForTest({DatabaseConnection.class})
public class ConstructorMockTest {@Testpublic void mockConstructor() throws Exception {// 1. 创建Mock实例DatabaseConnection mockConn = mock(DatabaseConnection.class);when(mockConn.isConnected()).thenReturn(true);// 2. Mock构造函数,返回Mock对象PowerMockito.whenNew(DatabaseConnection.class).withAnyArguments().thenReturn(mockConn);// 3. 测试代码中调用构造函数时,返回Mock对象DatabaseConnection conn = new DatabaseConnection("jdbc:url");assertTrue(conn.isConnected());}
}

缺点

  • 强耦合于JUnit 4,与JUnit 5整合复杂。
  • 配置繁琐,需使用特定Runner和@PrepareForTest
  • 项目依赖增加,可能引发版本冲突。

3. 方案二:使用Mockito-Inline(现代方案)

Mockito 3.4+ 提供Inline Mock Maker,支持静态方法Mock(无需PowerMock),但功能有限。

3.1 环境配置

确保Mockito版本≥3.4.0:

<dependency><groupId>org.mockito</groupId><artifactId>mockito-inline</artifactId><version>5.12.0</version><scope>test</scope>
</dependency>
3.2 Mock静态方法
import static org.mockito.Mockito.mockStatic;class MockitoInlineTest {@Testvoid mockStaticMethodWithInline() {// 1. 创建静态Mock作用域try (MockedStatic<StringUtils> mockedStatic = mockStatic(StringUtils.class)) {// 2. 配置静态方法行为mockedStatic.when(() -> StringUtils.isEmpty(anyString())).thenReturn(false);// 3. 执行测试逻辑assertFalse(StringUtils.isEmpty("test")); // 返回false// 4. 可选:验证静态方法调用mockedStatic.verify(() -> StringUtils.isEmpty("test"));}// 作用域外:静态方法恢复真实行为assertTrue(StringUtils.isEmpty("")); // 调用真实方法}
}
3.3 Mock构造函数

Mockito-Inline 不支持直接Mock构造函数,但可通过以下技巧间接实现:

@Test
void mockConstructorIndirectly() {try (MockedConstruction<DatabaseConnection> mockedConstruction = mockConstruction(DatabaseConnection.class)) {// 所有构造函数调用返回Mock对象DatabaseConnection mockConn = new DatabaseConnection("any_url");when(mockConn.isConnected()).thenReturn(true);// 测试逻辑assertTrue(mockConn.isConnected());}
}

优点

  • 兼容JUnit 5,无需特殊Runner。
  • 更轻量,减少依赖冲突风险。
  • 支持try-with-resources自动清理Mock状态。

限制

  • 静态方法Mock需在作用域内使用。
  • 构造函数Mock功能较弱,无法精确匹配参数。

4. 最佳实践与注意事项
场景推荐方案
新项目优先使用Mockito-Inline,尽量避免静态方法/构造函数的Mock需求。
遗留系统维护可短期使用PowerMock,逐步重构代码。
简单静态方法MockMockito-Inline + mockStatic()
精确构造函数MockPowerMock的whenNew()

通用建议

  • 重构优先:将静态方法调用封装为实例方法,通过依赖注入解耦。
  • 减少使用:静态方法Mock会破坏测试隔离性,增加维护成本。
  • 版本兼容:Mockito-Inline需Java 11+,PowerMock兼容Java 8但更新缓慢。

5. 综合示例:日期工具类测试

被测代码

public class OrderService {public String createOrderId() {String timestamp = LocalDate.now().toString(); // 静态方法now()return "ORDER_" + timestamp.replace("-", "");}
}

测试代码(Mockito-Inline)

class OrderServiceTest {@Testvoid createOrderId_ShouldFormatDate() {// 固定当前日期为2023-10-01try (MockedStatic<LocalDate> mockedLocalDate = mockStatic(LocalDate.class)) {LocalDate fixedDate = LocalDate.of(2023, 10, 1);mockedLocalDate.when(LocalDate::now).thenReturn(fixedDate);OrderService service = new OrderService();String orderId = service.createOrderId();assertEquals("ORDER_20231001", orderId);}}
}

通过合理选择工具和遵循最佳实践,可以在必要时有效处理静态方法和构造函数的Mock需求,同时保持测试代码的简洁性和可维护性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/17019.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

连通两台VMware虚拟机

连通两台VMware虚拟机 Fairing Winds and Following Seas VMware各模式的区别 在尝试连接之前&#xff0c;我们要搞清楚各模式的区别 简单来说就是&#xff0c;只有桥接模式和NAT模式是可以实现虚拟机联通的&#xff0c;而桥接模式和NAT模式分别对应了 V M w a r e VMware VM…

C++ 容器适配器

文章目录 1. 适配器2. stack和queue2.1 deque2.1.1 deque的底层结构2.1.2 deque如何实现头插和随机访问 2.2 用deque实现栈和队列2.3 deque的优缺点 3. priority_queue 1. 适配器 适配器是什么&#xff1f; 适配器是一种设计模式&#xff0c;实质上就是一种复用&#xff0c;即…

DeepSeek R1本地部署解决,DeepSeek服务繁忙

DeepSeek 本地部署是指将DeepSeek模型下载到本地电脑上&#xff0c;利用电脑的显卡进行数据处理和推理&#xff0c;可以减少网络延迟&#xff0c;提高数据处理和响应速度&#xff0c;从而避免将数据传输到云端&#xff0c;增强了数据的主权和控制&#xff0c;减少了因网络连接可…

GPT和BERT

笔记来源&#xff1a; Transformer、GPT、BERT&#xff0c;预训练语言模型的前世今生&#xff08;目录&#xff09; - B站-水论文的程序猿 - 博客园 ShusenWang的个人空间-ShusenWang个人主页-哔哩哔哩视频&#xff08;RNN模型与NLP应用&#xff09; 一、GPT 1.1 GPT 模型的…

深入浅出Java反射:掌握动态编程的艺术

小程一言反射何为反射反射核心类反射的基本使用获取Class对象创建对象调用方法访问字段 示例程序应用场景优缺点分析优点缺点 注意 再深入一些反射与泛型反射与注解反射与动态代理反射与类加载器 结语 小程一言 本专栏是对Java知识点的总结。在学习Java的过程中&#xff0c;学习…

JDK 14,15,17的一些新特性(部分常用)

1&#xff1a;instanceof&#xff08;后&#xff0c;使用不再需要墙转&#xff09; 2&#xff1a;switch语句增强 1&#xff1a;支持lmbda&#xff0c;自动防击穿&#xff0c;有返回值 2&#xff1a;支持case多个值&#xff0c;复杂逻辑结果支持yield返回 3&#xff1a;字符串…

活字格使用说明书

字格设计使用说明书 目录 1. 数据 2. 页面 3. 组件 4. 命令 一、数据 1.表数据创建(鼠标移动到表右击点击创建表) ‘ 图表 1 鼠标移至表1右击可重命名,添加字段输入所需字段名(一般数据类型的要注意:日期格式字段---日期、ID或者字典字段---整数、金…

springboot021校园周边美食探索及分享平台

版权声明 所有作品均为本人原创&#xff0c;提供参考学习使用&#xff0c;如需要源码数据库配套文档请移步 www.taobysj.com 搜索获取 技术实现 开发语言&#xff1a;Javavue。 框架&#xff1a;后端spingboot前端vue。 模式&#xff1a;B/S。 数据库&#xff1a;mysql。 开…

Kubernetes部署KeyDB服务

Kubernetes YAML 配置文件&#xff0c;部署一个 KeyDB 容器 vi keydb-deployment.yaml内容如下 apiVersion: apps/v1 kind: Deployment metadata:name: keydb-deployment spec:replicas: 1selector:matchLabels:app: keydbtemplate:metadata:labels:app: keydbspec:container…

新手自学:如何用gromacs对简单分子复合物进行伞形采样

1、建立体系: 1、将蛋白的pdb文件转化为gmx: gmx pdb2gmx -f 2BEG_model1_capped.pdb -ignh -ter -o complex.gro 这个网页可以实现将多肽序列转化为pdb: ProBuilder On-line 这个教程的蛋白2BFG包含两条链(chain A和B) 在生成的topol文件中,增加如下的内容,效果就…

如何使用Java语言在Idea和Android中分别建立服务端和客户端实现局域网聊天

手把手教你用Java语言在Idea和Android中分别建立服务端和客户端实现局域网聊天 目录 文章目录 手把手教你用**Java**语言在**Idea**和**Android**中分别建立**服务端**和**客户端**实现局域网聊天**目录**[toc]**基本实现****问题分析****服务端**Idea:结构预览Server类代码解…

金蝶云星空与马帮平台无缝对接,提高供应链效率

采购退货金蝶》马帮ok&#xff1a;系统对接集成案例分享 在企业的供应链管理中&#xff0c;数据的高效流转和准确处理至关重要。本文将聚焦于一个实际运行的系统对接集成案例——将金蝶云星空的数据集成到马帮平台&#xff0c;以实现采购退货数据的无缝传输和处理。 为了确保…

GPT-4o微调SFT及强化学习DPO数据集构建

假设&#xff0c;已经标注的训练数据集df包含了提示词、输入和输出三列。 构建微调SFT的数据集代码如下&#xff1a; data [] for x in df.values:prompt x[1]user_content x[2]assistant_content x[3]data.append({"messages": [{"role": "sys…

鸿蒙HarmonyOS NEXT开发:横竖屏切换开发实践

文章目录 一、概述二、窗口旋转说明1、配置module.json5的orientation字段2、调用窗口的setPreferredOrientation方法 四、性能优化1、使用自定义组件冻结2、对图片使用autoResize3、排查一些耗时操作 四、常见场景示例1、视频类应用横竖屏开发2、游戏类应用横屏开发 五、其他常…

02.10 TCP之文件传输

1.思维导图 2.作业 服务器代码&#xff1a; #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> …

Qt 控件整理 —— 按钮类

一、PushButton 1. 介绍 在Qt中最常见的就是按钮&#xff0c;它的继承关系如下&#xff1a; 2. 常用属性 3. 例子 我们之前写过一个例子&#xff0c;根据上下左右的按钮去操控一个按钮&#xff0c;当时只是做了一些比较粗糙的去演示信号和槽是这么连接的&#xff0c;这次我们…

1.Excel:某停车场计划调整收费标准❗(13)

目录 函数VLOOKUP ROUNDUP/ROUNDDOWN函数 NO1​ NO2会计专用类型​ NO3收费标准VLOOKUP​ NO4停放时间&#xff08;天&#xff09;​ NO5金额roundup/rounddown​ ​NO6汇总行​ NO7单元格突出显示​ NO8数据透视表​ 函数VLOOKUP VLOOKUP(收费标准!A3:B5 F4&#xf…

玩转大语言模型——使用Kiln AI可视化环境进行大语言模型微调数据合成

系列文章目录 玩转大语言模型——使用langchain和Ollama本地部署大语言模型 玩转大语言模型——三分钟教你用langchain提示词工程获得猫娘女友 玩转大语言模型——ollama导入huggingface下载的模型 玩转大语言模型——langchain调用ollama视觉多模态语言模型 玩转大语言模型—…

OpenAI推出的Computer Use智能体:Operator是什么

OpenAI推出的Computer Use智能体:Operator是什么 是一款能像人一样与图形用户界面交互来操作计算机的AI智能体。以下是其核心原理及举例说明: 核心原理 感知: 屏幕截图获取:利用高性能屏幕捕获模块,如基于WebRTC的截图技术,以极低延迟获取高清晰度页面图像,为后续分析…

k8s部署logstash

1. 编写logstash.yaml配置文件 --- apiVersion: v1 kind: Service metadata:name: logstash spec:type: ClusterIPclusterIP: Noneports:- name: logstash-tcpport: 5000targetPort: 5000- name: logstash-beatsport: 5044targetPort: 5044- name: logstash-apiport: 9600targ…