当前位置: 首页 > article >正文

Mockito 单测入门

Mockito 单测入门Spring Boot 项目中最精简的 Mockito 示例 — Service / 三方依赖 / Controller1 被测代码准备以下是一个简单的聊天消息服务内含需要测试的三种典型场景。ServicepublicclassChatMsgService{AutowiredprivateChatMsgRepositoryrepo;// Spring 注入AutowiredprivateSmsClientsmsClient;// 三方依赖如阿里云短信 SDKpublicChatMsgsend(Integeruid,Stringmessage){ChatMsgmsgnewChatMsg();msg.setUid(uid);msg.setMessage(message);msg.setCreateTime(LocalDateTime.now());returnrepo.save(msg);// 调用 Spring Bean}publicStringsendVerifyCode(Stringphone){Stringcode123456;smsClient.send(phone,code);// 调用三方 SDKreturncode;}}RestControllerRequestMapping(/chat)publicclassChatMsgController{AutowiredprivateChatMsgServiceservice;PostMapping(/send)publicChatMsgsend(RequestParamIntegeruid,RequestParamStringmessage){returnservice.send(uid,message);}}2 依赖配置dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencyspring-boot-starter-test已包含 Mockito、MockMvc、JUnit 5无需额外引入。3 Service 单测 — InjectMocks Mock核心Mock创建 Mock 对象InjectMocks自动注入到被测类。ExtendWith(MockitoExtension.class)// 启用 MockitoclassChatMsgServiceTest{MockprivateChatMsgRepositoryrepo;// 模拟 Spring BeanMockprivateSmsClientsmsClient;// 模拟三方依赖InjectMocksprivateChatMsgServiceservice;// 自动注入上面两个 mockTestvoidtestSend(){// 准备ChatMsgsavednewChatMsg();saved.setId(1L);saved.setUid(100);saved.setMessage(hello);Mockito.when(repo.save(Mockito.any())).thenReturn(saved);// 执行ChatMsgresultservice.send(100,hello);// 验证Assertions.assertEquals(1L,result.getId());Mockito.verify(repo,Mockito.times(1)).save(Mockito.any());}TestvoidtestSendVerifyCode(){// 执行Stringcodeservice.sendVerifyCode(13800138000);// 验证 — 不关心三方 SDK 内部实现只验证它被调用了Assertions.assertEquals(123456,code);Mockito.verify(smsClient,Mockito.times(1)).send(13800138000,123456);}}为什么三方依赖这么测短信 SDK 真实发送会扣费且依赖网络。用Mock让它什么都不做我们只验证 service 正确调用了它并返回了预期结果。4 Controller 单测 — WebMvcTest MockMvc只加载 Web 层Service 用MockBean注入 Mock。WebMvcTest(ChatMsgController.class)// 只启动 Controller 层classChatMsgControllerTest{AutowiredprivateMockMvcmockMvc;// HTTP 模拟客户端MockBeanprivateChatMsgServiceservice;// 模拟 ServiceTestvoidtestSend()throwsException{// 准备ChatMsgmockResultnewChatMsg();mockResult.setId(1L);mockResult.setUid(100);mockResult.setMessage(hello);Mockito.when(service.send(100,hello)).thenReturn(mockResult);// 执行 验证 — 模拟 HTTP 请求断言响应mockMvc.perform(MockMvcRequestBuilders.post(/chat/send).param(uid,100).param(message,hello)).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.jsonPath($.id).value(1)).andExpect(MockMvcResultMatchers.jsonPath($.message).value(hello));}}5 Controller POST JSON 参数测试当接口接收 JSON 请求体时使用RequestBody接收参数测试时通过.contentType(MediaType.APPLICATION_JSON).content()传入 JSON 字符串。PostMapping(/sendJson)publicChatMsgsendJson(RequestBodyChatMsgRequestreq){returnservice.send(req.getUid(),req.getMessage());}// 配合的 DTOpublicclassChatMsgRequest{privateIntegeruid;privateStringmessage;publicIntegergetUid(){returnuid;}publicvoidsetUid(Integeruid){this.uiduid;}publicStringgetMessage(){returnmessage;}publicvoidsetMessage(Stringmessage){this.messagemessage;}}TestvoidtestSendJson()throwsException{// 准备ChatMsgmockResultnewChatMsg();mockResult.setId(1L);mockResult.setUid(100);mockResult.setMessage(hello);Mockito.when(service.send(100,hello)).thenReturn(mockResult);// JSON 请求体StringjsonBody{\uid\:100,\message\:\hello\};// 执行 验证mockMvc.perform(MockMvcRequestBuilders.post(/chat/sendJson).contentType(MediaType.APPLICATION_JSON).content(jsonBody)).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.jsonPath($.id).value(1));}关键点.contentType(MediaType.APPLICATION_JSON)告诉 Spring 请求体是 JSON 格式.content(jsonBody)传入 JSON 字符串。注意 JSON 中的引号需要转义。6 Controller Header 传参测试接口需要从 Header 中获取参数如 token、traceId时使用RequestHeader注入测试时通过.header(key, value)传入。PostMapping(/sendWithToken)publicChatMsgsendWithToken(RequestHeader(token)Stringtoken,RequestParamIntegeruid,RequestParamStringmessage){// token 可用于鉴权这里省略校验逻辑returnservice.send(uid,message);}TestvoidtestSendWithToken()throwsException{// 准备ChatMsgmockResultnewChatMsg();mockResult.setId(1L);mockResult.setUid(100);mockResult.setMessage(hello);Mockito.when(service.send(100,hello)).thenReturn(mockResult);// 执行 验证 — 通过 .header() 传入请求头mockMvc.perform(MockMvcRequestBuilders.post(/chat/sendWithToken).header(token,abc123).param(uid,100).param(message,hello)).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.jsonPath($.id).value(1));}关键点.header(token, abc123)模拟 HTTP 请求头。可调用多次传入多个 header。如果有多个同名 header 需要传多个值使用.header(key, value1, value2)或.header(key, new String[]{v1,v2})。7 常用 Mockito API 速查// ---- 打桩 ----when(foo.bar()).thenReturn(xxx);// 返回固定值when(foo.bar()).thenThrow(newRuntimeException());// 抛异常when(foo.bar(anyInt())).thenAnswer(inv-42);// 动态返回// ---- 验证 ----verify(foo).bar();// 是否调用过verify(foo,times(2)).bar();// 调用次数verify(foo,never()).bar();// 从未调用verifyNoInteractions(foo);// 无任何交互// ---- 匹配器 ----any()anyInt()anyString()anyList()anyLong()anyBoolean()any(LocalDateTime.class)8 静态方法 Mock — mockStatic静态方法如工具类用Mockito.mockStatic()需要在 try-with-resources 块内使用mock 作用域仅限该块。ServicepublicclassChatMsgService{publicChatMsgsendWithMd5(Integeruid,Stringmessage){Stringmd5DigestUtils.md5DigestAsHex(// 静态方法调用message.getBytes());ChatMsgmsgnewChatMsg();msg.setUid(uid);msg.setMessage(message_md5);returnrepo.save(msg);}}TestvoidtestSendWithMd5(){// try-with-resources 包裹超出代码块自动失效try(MockedStaticDigestUtilsmockedMockito.mockStatic(DigestUtils.class)){// 打桩当调用静态方法时返回固定值mocked.when(()-DigestUtils.md5DigestAsHex(Mockito.any())).thenReturn(fake_md5);// 执行ChatMsgresultservice.sendWithMd5(100,hello);// 验证静态方法被调用mocked.verify(()-DigestUtils.md5DigestAsHex(Mockito.any()),Mockito.times(1));Assertions.assertTrue(result.getMessage().contains(fake_md5));}// 退出 try 块后静态 mock 自动失效不影响其他测试}// 异常模拟 TestvoidtestRepoThrows(){// 模拟 Spring Bean 抛异常Mockito.when(repo.save(Mockito.any())).thenThrow(newRuntimeException(DB down));Assertions.assertThrows(RuntimeException.class,()-service.send(100,hello));}TestvoidtestStaticMethodThrows(){try(MockedStaticDigestUtilsmockedMockito.mockStatic(DigestUtils.class)){// 模拟静态方法抛异常mocked.when(()-DigestUtils.md5DigestAsHex(Mockito.any())).thenThrow(newIllegalArgumentException(bad input));Assertions.assertThrows(IllegalArgumentException.class,()-service.sendWithMd5(100,hello));}}注意Mockito 静态 mock 需要 Mockito 3.4.0 和mockito-inline依赖。Spring Boot 2.5 / 3.x 的spring-boot-starter-test默认已包含无需额外配置。9 一句话总结场景做法注解Service 单测Mock 掉 Repository 和第三方 SDKMockInjectMocks三方依赖直接用Mock只验证调用了对应方法MockController 单测MockMvc 模拟 HTTP 请求MockBean 掉 ServiceWebMvcTestMockBean注解启动 Spring替换容器 Bean用在什么测试Mock否否Service 单测不启动 SpringMockBean是是Controller / 集成测试需 Spring 容器InjectMocks否否配合Mock把 mock 塞进手动创建的被测类

相关文章:

Mockito 单测入门

Mockito 单测入门 Spring Boot 项目中最精简的 Mockito 示例 — Service / 三方依赖 / Controller1 被测代码准备 以下是一个简单的聊天消息服务,内含需要测试的三种典型场景。 Service public class ChatMsgService {Autowiredprivate ChatMsgRepository repo; …...

百万Token免费用:DeepSeek V4今日全面开放,AI理解力迎来真正普惠

大家好,我是LeafStay。AI科技 今天(4月26日),一件对很多人来说可能会改变工作方式的事情悄悄发生了。国家超算互联网平台正式上线 DeepSeek-V4 限时免费对话服务。核心卖点只有一个:百万Token超长上下文,免…...

HTTP 4xx状态码绕过技术解析与byp4xx工具实战指南

1. 项目概述:一个绕过HTTP 4xx状态码的瑞士军刀 在Web安全测试和日常开发调试中,遇到403 Forbidden、401 Unauthorized这类4xx状态码是家常便饭。它们像一堵墙,告诉你“此路不通”。但很多时候,这堵墙并非坚不可摧,它可…...

airPLS算法突破性革新:无人干预的智能基线校正技术

airPLS算法突破性革新:无人干预的智能基线校正技术 【免费下载链接】airPLS baseline correction using adaptive iteratively reweighted Penalized Least Squares 项目地址: https://gitcode.com/gh_mirrors/ai/airPLS 在光谱分析、色谱检测和生物医学信号…...

工业现场零停机适配MCP 2026的4小时黄金窗口期——基于eBPF实时流量染色的无感协议升级法

更多请点击: https://intelliparadigm.com 第一章:工业现场零停机适配MCP 2026的4小时黄金窗口期——基于eBPF实时流量染色的无感协议升级法 在严苛的工业控制现场,MCP(Modbus Control Protocol)协议栈升级常因设备不…...

VS Code Copilot Next 自动化工作流配置:1个settings.json+2个task.json+3个AI提示工程=日均节省2.7小时

更多请点击: https://intelliparadigm.com 第一章:VS Code Copilot Next 自动化工作流配置实战案例 启用 Copilot Next 扩展与环境准备 在 VS Code 1.90 版本中,需先安装官方预览版扩展 Copilot Next(ID: github.copilot-next…...

轻量级知识库引擎Lore:文件驱动架构与自托管部署实践

1. 项目概述:一个为现代应用设计的轻量级知识库引擎最近在折腾个人项目和团队内部文档时,我又一次被那些“重量级”的知识库系统给劝退了。要么是部署复杂,对服务器资源要求高;要么是功能过于臃肿,90%的功能都用不上&a…...

神经网络模型容量控制:节点数与层数优化指南

1. 神经网络模型容量控制的核心逻辑在深度学习实践中,模型容量(Model Capacity)直接决定了神经网络的学习能力和泛化表现。就像给不同体型的人挑选衣服——太紧会限制行动(欠拟合),太松又显得臃肿&#xff…...

caj2pdf:3个技巧让知网CAJ文献在Linux上重获新生

caj2pdf:3个技巧让知网CAJ文献在Linux上重获新生 【免费下载链接】caj2pdf Convert CAJ (China Academic Journals) files to PDF. 转换中国知网 CAJ 格式文献为 PDF。佛系转换,成功与否,皆是玄学。 项目地址: https://gitcode.com/gh_mirr…...

NDIR CO2传感器技术与RRH47000-EVK评估板应用

1. RRH47000-EVK评估板与NDIR CO2传感器技术解析在环境监测和工业自动化领域,精确的CO2浓度测量正变得日益重要。Renesas最新推出的RRH47000-EVK评估板搭载了基于非分散红外(NDIR)技术的RRH47000 CO2传感器,为工程师提供了一套完整的开发解决方案。这套系…...

从零到一:计算机校招求职实战指南与面试宝典深度解析

从零到一:计算机校招求职实战指南与面试宝典深度解析 【免费下载链接】InterviewGuide 🔥🔥「InterviewGuide」是阿秀从校园->职场多年计算机自学过程的记录以及学弟学妹们计算机校招&秋招经验总结文章的汇总,包括但不限于…...

剪映专业版教程:制作旋转音乐碟片效果

前言 今天教大家一个旋转音乐碟片效果。这种效果模拟黑胶唱片或CD在播放器中旋转的场景,配合歌曲播放、歌词显示和复古贴纸,适合音乐分享、怀旧金曲、情感短片等场景。 效果预览:碟片从上往下滑入播放器凹槽,开始旋转播放歌曲&a…...

郑州全自动无塔供水压力罐厂家怎么选?这些经验实测能帮到你

2026 年,很多人在选全自动无塔供水压力罐厂家时犯了难。其实,选对厂家能解决不少供水难题。河南飞龙圣无塔供水设备有多年行业经验,能给大家分享一些实用的选择方法。不少人在选择无塔供水压力罐时踩过坑。有的买到的压力罐材质差&#xff0c…...

AI驱动安全审计工具:claude-security-audit实战解析与DevSecOps集成

1. 项目概述:一个面向开发者的AI驱动安全审计工具最近在折腾一个Web项目,上线前心里总是不踏实,担心代码里藏着什么安全漏洞,让项目刚起步就“出师未捷身先死”。手动审计吧,费时费力,还容易有疏漏&#xf…...

易语言本地网络验证系统源码免服务器

带简单的防破解和加密解密。 需要的自己下载吧。 我用夸克网盘分享了「本地验证l例程.zip」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。 链接:https://pan.quark.cn/s/d97…...

lvgl实现图标还原

隐藏很简单,在设计lvgl初始界面的时候添加事件即可,但是还原需要改代码本次修改需要在event事件那个文件进行修改,首先找到点击后隐藏的那个模块static void screen_1_click_img_event_handler (lv_event_t *e)click_img是我起的名字&#xf…...

智能结对编程工具the-pair:实时代码审查与AI辅助开发实践

1. 项目概述:一个为开发者设计的“结对编程”伴侣 如果你是一名开发者,尤其是经常需要独立完成项目或学习新技术的程序员,你一定体会过那种“卡壳”的孤独感。面对一个复杂的算法逻辑,或者一个陌生的技术栈,身边没有可…...

PyTorch实现逻辑回归:从原理到实战

1. 逻辑回归基础与PyTorch实现概览逻辑回归是机器学习中最基础但极其重要的分类算法,尽管名字中带有"回归",它实际上解决的是二分类问题。在PyTorch框架下实现逻辑回归,不仅能理解深度学习的基础构建块,还能掌握自定义模…...

RAGFlow · 第 3 章:第一节 RAGFlow 配置参数全景图与实验结论

系列导航 第 0 章 前言:为什么企业 AI 工程师必须掌握 RAGFlow第 1 章:安装部署与基础配置**——从零跑通第一个 RAG Pipeline第 2 章:RAGFlow RAGFlow 代码介绍第 3 章:攻克企业复杂文档——理解 DeepDoc、Naive、MinerU 与 Docl…...

NVIDIA Nemotron 3架构解析:智能体AI与混合Mamba-Transformer MoE设计

1. NVIDIA Nemotron 3架构解析:面向智能体AI的新一代模型设计在当今AI领域,智能体系统(Agentic AI)正变得越来越复杂。这类系统通常由多个协作的智能体组成——包括检索器、规划器、工具执行器和验证器等——它们需要在大量上下文…...

AI 时代最大的谎言:你以为在学习,其实在欠债—思维决定上限的反焦虑框架

文章目录1、写在前面:我为什么不再写"AI 焦虑"2、本文速览3、AI 焦虑的真实闭环:你不是在错过 AI3.1、焦虑的来源不是机会,是怕3.2、机会从来不属于"绝大多数人"3.3、对你的实际意义4、MIT 认知负债:所有 AI …...

每日一学:设计模式之观察者模式

观察者模式(Observer Pattern)属于行为型设计模式,核心定义:构建对象间一对多的依赖关系,当被观察者(发布者 / 主题)状态发生变化时,所有订阅它的观察者(订阅者&#xff…...

【2026年网易雷火春招- 4月26日-第一题- 喵居】(题目+思路+JavaC++Python解析+在线测试)

题目内容 在《忘川风华录》的喵居中,为了帮助名士猫完成进化,使君需要炼化出高阶的九世灵。 喵居的供台上目前散落着 nnn 团微小的「猫灵元魂」,第 iii 团元魂的灵力值为 aia_i...

Bluetooth Classic中的速率区别

0 Preface/Foreword1PHY介绍1.1 与BLE的区别BLE有PHY 1M和2M的区别,但是在Bluetooth Classic中,没有这个概念。因为PHY 1M和2M是BLE的专有术语。虽然BLE和Bluetooth Classic都是使用2.4GHz,但是走的两套不同的技术路线。1.2 PHY速率分类Bluet…...

智能电话录音总结,工具高精准识别快速整理,复盘通话超省心省事

最近试了2026年新迭代的这批智能电话录音总结工具,高精准识别加快速整理是真的香,现在复盘通话完全不用再熬大夜来回拖进度条扒内容,省心到我恨不得早两年用上。我做To B销售快三年,之前最头疼的就是每天打七八通客户电话&#xf…...

高效编程实践:用Codex告别重复造轮子

技术文章大纲:告别重复造轮子——Codex写脚本的高效实践核心概念与背景重复造轮子的定义:开发中重复实现已有功能的现象及其效率问题Codex的定位:AI辅助编程工具如何通过自然语言生成代码适用场景:快速原型开发、自动化脚本、代码…...

ChatGPT-CLI:终端集成AI助手,提升开发者效率的实战指南

1. 项目概述:一个让ChatGPT在终端里“安家”的命令行工具如果你和我一样,每天大部分时间都泡在终端(Terminal)里,那么你一定有过这样的体验:为了向ChatGPT提个问题,或者让它帮忙写段代码&#x…...

如何搭建逻辑备库_SQL Apply与不支持的数据类型评估

SQL Apply 启动失败主因是备库控制文件残留主库“只读”标记或角色未正确设为PHYSICAL STANDBY;需确保V$DATABASE中DATABASE_ROLEPHYSICAL STANDBY且OPEN_MODEMOUNTED,并清理V$DATAGUARD_CONFIG中重复DB_UNIQUE_NAME。SQL Apply 启动失败报 ORA-16000 或…...

华为HDC大会2024张平安总keynote盘古多模态生成大模型:STCG技术如何重塑自动驾驶数据引擎

从"娱乐生成"到"产业生成":盘古的差异化路径 当业界多模态大模型还在追逐一镜到底的娱乐视频生成时,盘古5.0选择了一条截然不同的技术路线——聚焦行业急需的价值场景。在华为HDC大会上,盘古团队首次系统披露了多模态生…...

GEEKOM GT1 Mega迷你主机Ubuntu 24.10性能评测

1. GEEKOM GT1 Mega迷你主机深度评测:Ubuntu 24.10下的Intel Core Ultra 9 185H体验 作为一名长期关注迷你主机的技术爱好者,最近我有机会对搭载Intel Core Ultra 9 185H处理器的GEEKOM GT1 Mega进行了全面测试。这款迷你主机在Windows 11 Pro环境下表现…...