Mock 单元测试

作者:小凯
沉淀、分享、成长,让自己和他人都能有所收获!

本文的宗旨在于通过简单干净实践的方式教会读者,如何使用 Mock (opens new window)进行工程的单元测试,以便于验证系统中的独立模块功能的健壮性。

从整个工程所处不同阶段的测试手段包括;单元测试、集成测试、系统测试、验收测试、性能测试、安全测试、回归测试,以及兼容、可靠、可用性测试。

而单元测试的重点在于,对工程开发中的代码,进行流程中的单元化测试。如一整个下单流程中,需要调用各项外部的接口(风控、账户、营销、试算、支付),才能完成整个下单流程。但在本地开发过程中,不太能将所有的外部接口都调试为开发环境可用状态,所有这个时候要做单元化测试,对于一些不能随时提供服务的接口进行 Mock (opens new window)处理。

一、案例背景
因为 Mock 单元测试的重点,主要体现在;功能流程较长、调用外部接口稳定性较差、测试过程中希望可以不启动 SpringBoot 应用就能对单个功能模块进行测试验证。

所以本章节带着这样一个案例背景的情况,这里通过 《HTTP 框架使用和场景实战 - 结合ChatGLM自动回帖!》 (opens new window)做一个小重构。来对 Mock 框架进行验证使用。
在这里插入图片描述

首先,这里使用 DDD 工程模型结构,搭建出测试工程。—— DDD 是一种软件设计方法,而软件的设计方法涵盖了;范式、模型、框架、方法论。所以通常下 MVC 与 DDD 的对比先从模型、框架在到思想设计和方法论。
之后,我们在这样的一个模型结构下,实现出自动回帖的领域功能。而这个模型的实现恰好需要调用外部的接口和 ChatGLM SDK,这与我们要做的 Mock 测试正好符合,因为在大部分开发场景下,远程的 HTTP 调用可能不不会一直可用,所以可以用 Mock 方式进行模拟。
二、功能实现
1. 工程结构
在这里插入图片描述

  • 在 domain 中实现一个zsxq的自动回帖领域,而它所需的要调用的接口则由基础设施层提供。
  • 另外在 app 中还有 ChatGLM SDK 的配置启动,也会被注入到 AiReply 实现类中。

2. Ai模块启动

# ChatGLM SDK Config
chatglm:sdk:config:# 状态;true = 开启、false 关闭enabled: false# 官网地址api-host: https://open.bigmodel.cn/# 官网申请 https://open.bigmodel.cn/usercenter/apikeysapi-secret-key: d570f7c5d289cdac2abdfdc562e39f3f.trqz1dH8ZK6ED7Pg
@Bean
@ConditionalOnProperty(value = "chatglm.sdk.config.enabled", havingValue = "true", matchIfMissing = false)
public OpenAiSession openAiSession(ChatGLMSDKConfigProperties properties) {// 1. 配置文件cn.bugstack.chatglm.session.Configuration configuration = new cn.bugstack.chatglm.session.Configuration();configuration.setApiHost(properties.getApiHost());configuration.setApiSecretKey(properties.getApiSecretKey());// 2. 会话工厂OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);// 3. 开启会话return factory.openSession();
}
  • 所有的这些配置类的服务,都可以放到 app下的 config 模块中。
  • ChatGLM 可以直接在官网申请,默认会赠送18元的额度,对于它所提供的模型,还是非常够测试使用的。

3. 基础设置 - 接口调用
3.1 接口 - 防腐对接
源码:cn.bugstack.xfg.dev.tech.infrastructure.gateway.api.IZSXQApi

public interface IZSXQApi {/*** 查询知识星球帖子内容** @return 帖子数据* @throws IOException 异常*/ResponseDTO topics() throws IOException;/*** 回复帖子** @param topicId 帖子ID* @param content 回复内容*/void comment(long topicId, String content);}
  • 在基础设置层中定义 gateway 网关接口调用,对于外部的接口使用,中间要做一层防腐,不要直接把外部的接口暴露出去使用。

3.2 使用 - 依赖倒置
源码:cn.bugstack.xfg.dev.tech.infrastructure.gateway.adapter.ZSXQAdapter

public class ZSXQAdapter implements IZSXQAdapter {@Resourceprivate IZSXQApi zsxqApi;@Overridepublic List<TopicsItemVO> queryTopics() {try {ResponseDTO responseDTO = zsxqApi.topics();RespData respData = responseDTO.getRespData();List<TopicsItem> topics = respData.getTopics();List<TopicsItemVO> topicsItemVOList = new ArrayList<>();for (TopicsItem topicsItem : topics) {TopicsItemVO topicsItemVO = TopicsItemVO.builder().topicId(topicsItem.getTopicId()).talk(topicsItem.getTalk().getText()).showCommentsItems(topicsItem.getShowComments() != null ? topicsItem.getShowComments().stream().map(showCommentsItem -> {TopicsItemVO.ShowCommentsItem item = new TopicsItemVO.ShowCommentsItem();item.setUserId(showCommentsItem.getOwner().getUserId());return item;}).collect(Collectors.toList()) : new ArrayList<>()).build();topicsItemVOList.add(topicsItemVO);}return topicsItemVOList;} catch (IOException e) {throw new RuntimeException(e);}}@Overridepublic boolean comment(long topicId, String content) {zsxqApi.comment(topicId, content);return true;}}
  • 注意,TopicsItemVO 对象来自于 domain 下领域中模型下的 VO 对象。因为是依赖倒置的,所以 infrastructure 引用的是 domain 并对其接口做实现处理。
  • 并且,TopicsItemVO 只是需要获取自己需要的对象,还可以做简单的封装处理。这样可以衔接外部接口和内部逻辑中间的桥梁,不做强关联。

4. 任务调度
源码:cn.bugstack.xfg.dev.tech.job.ReplyJob

public class ReplyJob {@Resourceprivate IAiReply aiReply;@Scheduled(cron = "0/10 * * * * ?")public void exec() throws Exception {log.info("自动回帖任务开始执行...");aiReply.doAiReply();}}
  • 现在在 trigger 触发器层中的 job 下,就可以调用我们已经实现好的 AiReply 自动回帖功能了。
  • 此外,注意 Application 中 @EnableScheduling 注解是开启的,否则任务不能执行。

三、系统测试
1. 集成测试

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApiTest {@Resourceprivate IAiReply aiReply;@Testpublic void test_IAiReply() {aiReply.doAiReply();}}
  • 通常情况下这种测试是最多的,写多少功能,就直接测试调用。如功能中所用到的;HTTP接口、RPC接口、数据库、Redis等资源,都会需要使用到。有时候也因为这样,所以不好测试。那么单元测试就出现了。

2. 单元测试

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class MockTest {@Resourceprivate IAiReply aiReply;@MockBeanprivate IZSXQAdapter izsxqAdapter;@Testpublic void test_doAiReply() throws InterruptedException, JsonProcessingException {Mockito.when(izsxqAdapter.queryTopics()).thenReturn(new ArrayList<TopicsItemVO>() {{TopicsItemVO topicsItemVO = new TopicsItemVO();topicsItemVO.setTopicId(10001L);topicsItemVO.setTalk("<e type=\"mention\" uid=\"241858242255511\" title=\"%40%E5%B0%8F%E5%82%85%E5%93%A5\" /> 提问 java 冒泡排序");add(topicsItemVO);}});Mockito.when(izsxqAdapter.comment(Mockito.anyLong(), Mockito.anyString())).thenReturn(true);aiReply.doAiReply();// 等待;ChatGLM 异步回复new CountDownLatch(1).await();}}

在这里插入图片描述

  • 在基于使用 SpringBoot 的启动,以及一部分功能需要走真实调用的情况下,另外一部分功能的接口可能没法调用时。可以使用这样的一种 MockBean 的方式进行处理,并对整条链路上调用到的接口方法进行 Mock 处理。`Mockito.when(调用到的接口).thenReturn(返回的结果);
  • 那么现在在测试方法中,做了2个Mock操作,把查询帖子和回复帖子,都给处理掉。也就是有了 Mock 以后,程序调用到这里,就直接走 Mock 里设置的结果信息了。

3. 功能测试

@Slf4j
@RunWith(MockitoJUnitRunner.class)
public class ZSXQAdapterTest {@Mockprivate IZSXQApi mockZsxqApi;@InjectMocksprivate ZSXQAdapter zsxqAdapterUnderTest;@Testpublic void testQueryTopics() throws Exception {// Setupfinal List<TopicsItemVO> expectedResult = Arrays.asList(TopicsItemVO.builder().topicId(0L).talk("talk").showCommentsItems(Arrays.asList(TopicsItemVO.ShowCommentsItem.builder().userId(0L).build())).build());// Configure IZSXQApi.topics(...).final ResponseDTO responseDTO = new ResponseDTO();final RespData respData = new RespData();final TopicsItem topicsItem = new TopicsItem();final ShowCommentsItem showCommentsItem = new ShowCommentsItem();final Owner owner = new Owner();owner.setUserId(0L);showCommentsItem.setOwner(owner);topicsItem.setShowComments(Arrays.asList(showCommentsItem));final Talk talk = new Talk();talk.setText("talk");topicsItem.setTalk(talk);topicsItem.setTopicId(0L);respData.setTopics(Arrays.asList(topicsItem));responseDTO.setRespData(respData);when(mockZsxqApi.topics()).thenReturn(responseDTO);// Run the testfinal List<TopicsItemVO> result = zsxqAdapterUnderTest.queryTopics();// Verify the resultsassertEquals(expectedResult, result);log.info("测试结果:{}", JSON.toJSONString(result));}}

在这里插入图片描述

  • 除了前面两种测试,我们在开发功能的时候,还有场景测试;不启动 SpringBoot 但希望对实现的功能进行测试。
  • 那么这里所体现的就是这样的测试,主要使用;@RunWith(MockitoJUnitRunner.class)、@Mock、@InjectMocks 相当于模拟了一个启动的过程,只不过都是 Mock 的信息。但你可以根据这些信息来调试你的接口。
  • 提示:你可以安装 IDEA Plugin Squaretest 它能自动的帮你生成Mock单元测试。这个插件是收费的,但还好不贵。

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

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

相关文章

MySQL 深度性能优化配置实战指南

🔧 一、硬件与系统层优化:夯实性能基石 ​​硬件选型策略​​ ​​CPU​​:读密集型场景选择多核CPU(如32核);写密集型场景选择高主频CPU(如3.5GHz+)。 ​​内存​​:建议≥64GB,​​缓冲池命中率≥99%​​ 是性能关键指标。 ​​存储​​:​​必用NVMe SSD​​,I…

Visual Studio Code(VSCode)中设置中文界面

在VS Code中设置中文界面主要有两种方法&#xff1a;通过扩展市场安装中文语言包或通过命令面板直接切换语言。‌方法一&#xff1a;通过扩展市场安装中文语言包‌打开VS Code&#xff0c;点击左侧活动栏的"扩展"图标&#xff08;或按CtrlShiftX&#xff09;。在搜索…

叉车机器人如何实现托盘精准定位?这项核心技术的原理和应用是什么?

随着智慧物流和智能制造的加速发展&#xff0c;智能化转型成为提升效率、降低成本的关键路径&#xff0c;叉车机器人&#xff08;AGV/AMR叉车&#xff09;在仓储、制造、零售等行业中的应用日益广泛。 其中&#xff0c;托盘定位技术是实现其高效、稳定作业的核心环节之一&…

NO.6数据结构树|二叉树|满二叉树|完全二叉树|顺序存储|链式存储|先序|中序|后序|层序遍历

树与二叉树的基本知识 树的术语结点&#xff1a; 树中的每个元素都称为结点&#xff0c; 例如上图中的 A,B,C…根结点&#xff1a; 位于树顶部的结点&#xff0c; 它没有父结点,比如 A 结点。父结点&#xff1a; 若一个结点有子结点&#xff0c; 那么这个结点就称为其子结点的父…

数据集下载网站

名称简介链接Kaggle世界上最大的数据科学竞赛平台之一&#xff0c;有大量结构化、图像、文本等数据集可直接下载✅支持一键下载、APIPapers with Code可按任务&#xff08;如图像分类、文本生成等&#xff09;查找模型与数据集&#xff0c;标注 SOTA✅与论文强关联Hugging Face…

Tomcat 生产 40 条军规:容量规划、调优、故障演练与安全加固

&#xff08;一&#xff09;容量规划 6 条 军规 1&#xff1a;线程池公式 maxThreads ((并发峰值 平均 RT) / 1000) 冗余 20 %&#xff1b; 踩坑&#xff1a;压测 2000 QPS、RT 200 ms&#xff0c;理论 maxThreads500&#xff0c;线上却设 150 导致排队。军规 2&#xff1a;…

深入解析 Amazon Q:AWS 推出的企业级生成式 AI 助手

在人工智能助手竞争激烈的当下&#xff0c;AWS 重磅推出的 Amazon Q 凭借其强大的企业级整合能力&#xff0c;正成为开发者提升生产力的新利器。随着生成式 AI 技术席卷全球&#xff0c;各大云厂商纷纷布局智能助手领域。在 2023 年 re:Invent 大会上&#xff0c;AWS 正式推出了…

物流自动化WMS和WCS技术文档

导语大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。欢迎大家使用我们的仓储物流技术AI智能体。新书《智能物流系统构成与技术实践》新书《智能仓储项目出海-英语手册&#xff0c;必备&#xff01;》完整版文件和更多学习资料&#xff0c;…

Web3.0 实战项目、简历打造、精准投递+面试准备

目录 一、获取真实企业级 Web3.0 项目的 5 种方式 1. 参与开源项目&#xff08;推荐指数&#xff1a;⭐⭐⭐⭐⭐&#xff09; 2. 参与黑客松&#xff08;Hackathon&#xff09; 3. 远程实习 & DAO 协作项目&#xff08;兼职也可&#xff09; 4. Web3 Startup 实战项目合…

pymongo库:简易方式存取数据

文档 基础使用 前提&#xff1a;开发机器已安装mongo配置环境&#xff0c;已启动服务。 macOS启动服务&#xff1a;brew services start mongodb-community8.0 macOS停止服务&#xff1a;brew services stop mongodb-community8.0安装&#xff1a;python3 -m pip install pym…

Java 线程池与多线程并发编程实战全解析:从异步任务调度到设计模式落地,200 + 核心技巧、避坑指南与业务场景结合

多线程编程在现代软件开发中扮演着至关重要的角色&#xff0c;它能够显著提升应用程序的性能和响应能力。通过合理利用异步线程、多线程以及线程池等技术&#xff0c;我们可以更高效地处理复杂任务&#xff0c;优化系统资源的使用。同时&#xff0c;在实际应用中&#xff0c;我…

gitee 分支切换

ssh-keygen -t rsa -C "pengchengzhangcplaser.com.cn" ssh -T gitgitee.comgit remote add origin 仓库地址git config --global user.email "youexample.com"git config --global user.name "Your Name"# 1. 更新远程信息 git fetch origin# …

Vue3生命周期函数

在 Vue 3 中&#xff0c;生命周期钩子函数是指组件从创建到销毁的整个过程中&#xff0c;Vue 自动调用的一些特定函数。它们让你能够在组件的不同阶段执行一些自定义操作。Vue 3 提供了组合式 API 和选项式 API 两种方式来定义生命周期钩子。1. onBeforeMount (组合式 API)作用…

基于SEP3203微处理器的嵌入式最小硬件系统设计

目录 1 引言 2 嵌入式最小硬件系统 3 SEP3202简述 4 最小系统硬件的选择和单元电路的设计 4.1 电源电路 4.2 晶振电路 4.3 复位及唤醒电路 4.5 存储器 4.5.1 FLASH存储 4.5.2 SDRAM 4.6 串行接口电路设计 4.7 JTAG模块 4.8 扩展功能&#xff08;LED&#xff09; …

【开源软件推荐】 SmartSub,一个可以快速识别视频/音频字幕的工具

背景介绍 我就说Github上面能找到好东西吧 事情是这样的 我最近在用PC端的剪映剪辑视频 需要用到它的语音转字幕功能 转完之后&#xff0c;导出的时候 发现 赫然有一项字幕识别的会员权益 我寻思看看什么价格 不贵的话就充了 好家伙&#xff0c;这不看不知道&#xff…

自动驾驶仿真领域常见开源工具

自动驾驶仿真领域常见开源工具1、目录1.1 自动驾驶仿真领域常见开源2、地图&场景2.1、场景播放器-Esmini4、被测对象-智驾软件4.1、Autoware4.4、端到端模型-VAD4.5、端到端模型-UniAD4.6、端到端模型-ThinkTwice4.7、端到端模型-TCP5、评价方法5.1、Leaderboard5.2、Bench…

GPU算力租用平台推荐,价格便宜且有羊毛薅,最低只要0.49/小时!

1.趋动云&#xff0c;这是我近期一直在用的&#xff0c;使用体验还不错&#xff0c;推荐给大家 网址&#xff1a;https://platform.virtaicloud.com/gemini_web/auth/register?inviteCode5f74065eac6d8867eac5c82194e2683a 是否选择一个算力平台我认为有几点需要考虑&#xff…

python学智能算法(二十五)|SVM-拉格朗日乘数法理解

引言 前序学习进程中&#xff0c;已经对最佳超平面的求解有了一定认识。 刚好在此梳理一下: 函数距离 首先有函数距离F&#xff0c;也可以称为函数间隔F&#xff1a; Fmin⁡i1...myi(w⋅xib)F \min_{i1...m}y_{i}(w \cdot x_{i}b)Fi1...mmin​yi​(w⋅xi​b) 几何距离 然后…

vscode 源码编译

windows 环境 下载安装 build tools Visual Studio Build Tools 勾选 C 因为安装详细信息里是 v143&#xff0c;所以单个组件里也要追加两个 143 的勾选 点击安装&#xff0c;安装好重启下电脑 Electron 安装失败&#xff1a;connect ETIMEDOUT 20.205.243.166:443 为防Ele…

读取和写入json,xml文件

一、JSON文件操作​ 1. 核心类​​ ​​QJsonDocument​​&#xff1a;表示整个JSON文档&#xff0c;提供解析&#xff08;fromJson()&#xff09;和序列化&#xff08;toJson()&#xff09;功能。 ​​QJsonObject​​&#xff1a;存储键值对集合&#xff0c;支持嵌套对象和数…