使用 JUnitnd Mockito 对图像上传器 API 进行单元测试

使用 junitnd mockito 对图像上传器 api 进行单元测试

在本系列的第一篇文章中,我们逐步介绍了如何使用 spring boot、cloudinary、docker 和 postgresql 构建一个强大的图像上传器。我们涵盖了从设置项目到向保存图像和信息的端点发出请求的所有内容。如果您还没有阅读那篇文章,我强烈建议您从那里开始,为我们将要使用的应用程序打下坚实的基础。

现在,是时候确保我们的应用程序可靠并随着时间的推移保持其完整性。这给我们带来了软件开发的一个关键方面:测试。在本文中,我们将重点为我们的图像上传器 api 编写单元测试。我们将探索如何模拟依赖关系,并编写涵盖服务不同部分的测试。

单元测试不仅有助于及早发现错误,还能确保我们的代码可维护和可扩展。在本文结束时,您将拥有一套针对图像上传器 api 的全面测试,让您确信您的应用程序按预期工作。

让我们深入单元测试的世界,让我们的图像上传器 api 防弹!

配置

我正在使用 vscode 和 java 扩展包。现在我们准备好编写测试了。

如果您使用其他 ide,请参阅 junit5 文档中对所有这些 ide 的支持。

图酷AI 图酷AI

下载即用!可以免费使用的AI图像处理工具,致力于为用户提供最先进的AI图像处理技术,让图像编辑变得简单高效。

图酷AI 57 查看详情 图酷AI

测试

1. 图书服务测试

右键单击 bookservice 类,单击“go to test”,然后从菜单中选择要为其生成测试的方法。

将会生成一个类似的文件,如下所示:

import org.junit.jupiter.api.test;public class bookservicetest {    @test    void testaddbook() {    }}

请记住,对于本文,我们将使用 aaa 模式 进行测试(排列 – 执行 – 断言)。

1.1.模拟属性

@extendwith(mockitoextension.class)public class bookservicetest {    @mock    private bookrepository bookrepository;    @mock    private cloudinary cloudinary;    @mock    private multipartfile multipartfile;    @mock    private uploader uploader;    @captor    private argumentcaptor bookargumentcaptor;    @injectmocks    private bookservice bookservice;}

@mock 注释模拟/模拟类将要使用的属性或依赖项的行为。@injectmocks 注解创建模拟并将其注入到相应的字段中。

1.2.编写测试

测试成功案例(shouldcreateanewbook)。测试对存储库的调用(shouldcallrepositorysave)。测试上传是否失败(shouldfailtheupload)。

@extendwith(mockitoextension.class)public class bookservicetest {    @mock    private bookrepository bookrepository;    @mock    private cloudinary cloudinary;    @mock    private multipartfile multipartfile;    @mock    private uploader uploader;    @captor    private argumentcaptor bookargumentcaptor;    @injectmocks    private bookservice bookservice;    @nested    class addbook {        @test        void shouldcreateanewbook() throws exception {            // arrange            map uploadresult = map.of("url", "http://example.com/image.jpg");            when(cloudinary.uploader()).thenreturn(uploader);            when(uploader.upload(any(file.class), anymap())).thenreturn(uploadresult);            book book = new book();            book.setname("test book");            book.setimgurl(uploadresult.get("url").tostring());            when(bookrepository.save(any(book.class))).thenreturn(book);            when(multipartfile.getoriginalfilename()).thenreturn("test.jpg");            when(multipartfile.getbytes()).thenreturn("test content".getbytes());            // act            book result = bookservice.addbook("test book", multipartfile);            // assert            assertnotnull(result);            assertequals("test book", result.getname());            assertequals("http://example.com/image.jpg", result.getimgurl());        }        @test        void shouldcallrepositorysave() throws exception {            // arrange            map uploadresult = map.of("url", "http://example.com/image.jpg");            when(cloudinary.uploader()).thenreturn(uploader);            when(uploader.upload(any(file.class), anymap())).thenreturn(uploadresult);            book book = new book();            book.setname("test book");            book.setimgurl(uploadresult.get("url").tostring());            when(bookrepository.save(any(book.class))).thenreturn(book);            when(multipartfile.getoriginalfilename()).thenreturn("test.jpg");            when(multipartfile.getbytes()).thenreturn("test content".getbytes());            // act            bookservice.addbook("test book", multipartfile);            // assert            verify(bookrepository, times(1)).save(bookargumentcaptor.capture());            book capturedbook = bookargumentcaptor.getvalue();            assertequals("test book", capturedbook.getname());            assertequals("http://example.com/image.jpg", capturedbook.getimgurl());        }        @test        void shouldfailtheupload() throws exception {            // arrange            when(multipartfile.getoriginalfilename()).thenreturn("test.jpg");            when(multipartfile.getbytes()).thenreturn("test content".getbytes());            when(cloudinary.uploader()).thenreturn(uploader);            when(uploader.upload(any(file.class),                    anymap())).thenthrow(ioexception.class);            // act & assert            responsestatusexception exception = assertthrows(responsestatusexception.class, () -> {                bookservice.addbook("test book", multipartfile);            });            assertequals(httpstatus.bad_gateway, exception.getstatuscode());            assertequals("failed to upload the file.", exception.getreason());        }    }}

2. 图书控制器测试

测试成功案例(shouldreturnsuccess)测试失败案例(shouldfailtouploadimage)使用缺少的名称参数进行测试(shouldfailwithmissingnameparameter)使用缺少的 imgurl 参数进行测试(shouldfailwithmissingimageparameter)

package cloudinary.upload.imageUpload.controllers;import static org.mockito.ArgumentMatchers.any;import static org.mockito.Mockito.when;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;import org.junit.jupiter.api.Nested;import org.junit.jupiter.api.Test;import org.junit.jupiter.api.extension.ExtendWith;import org.mockito.InjectMocks;import org.mockito.Mock;import org.mockito.junit.jupiter.MockitoExtension;import org.springframework.http.HttpStatus;import org.springframework.http.MediaType;import org.springframework.mock.web.MockMultipartFile;import org.springframework.test.web.servlet.MockMvc;import org.springframework.test.web.servlet.setup.MockMvcBuilders;import org.springframework.web.server.ResponseStatusException;import cloudinary.upload.imageUpload.configs.GlobalExceptionHandler;import cloudinary.upload.imageUpload.entities.Book;import cloudinary.upload.imageUpload.services.BookService;@ExtendWith(MockitoExtension.class)public class BookControllerTest {    @Mock    private BookService bookService;    @InjectMocks    private BookController bookController;    private MockMvc mockMvc;    @Nested    class AddBook {        @Test        void shouldReturnSuccess() throws Exception {            // Arrange            MockMultipartFile image = new MockMultipartFile("imgUrl", "test.jpg", MediaType.IMAGE_JPEG_VALUE,                    "test content".getBytes());            Book book = new Book();            book.setName("Test Book");            book.setImgUrl("http://example.com/image.jpg");            when(bookService.addBook(any(String.class), any(MockMultipartFile.class))).thenReturn(book);            mockMvc = MockMvcBuilders.standaloneSetup(bookController).build();            // Act & Assert            mockMvc.perform(multipart("/addBook")                    .file(image)                    .param("name", "Test Book"))                    .andExpect(status().isOk())                    .andExpect(jsonPath("$.name").value("Test Book"))                    .andExpect(jsonPath("$.imgUrl").value("http://example.com/image.jpg"));        }        @Test        void shouldFailToUploadImage() throws Exception {            // Arrange            MockMultipartFile image = new MockMultipartFile("imgUrl", "test.jpg", MediaType.IMAGE_JPEG_VALUE,                    "test content".getBytes());            when(bookService.addBook(any(String.class), any(MockMultipartFile.class)))                    .thenThrow(new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,                            "Failed to upload the file."));            mockMvc = MockMvcBuilders.standaloneSetup(bookController).setControllerAdvice(new GlobalExceptionHandler())                    .build();            // Act & Assert            mockMvc.perform(multipart("/addBook")                    .file(image)                    .param("name", "Test Book"))                    .andExpect(status().isInternalServerError())                    .andExpect(result -> result.getResponse().equals("Failed to upload the file."));        }        @Test        void shouldFailWithMissingNameParameter() throws Exception {            // Arrange            MockMultipartFile image = new MockMultipartFile("imgUrl", "test.jpg", MediaType.IMAGE_JPEG_VALUE,                    "test content".getBytes());            mockMvc = MockMvcBuilders.standaloneSetup(bookController).build();            // Act & Assert            mockMvc.perform(multipart("/addBook")                    .file(image))                    .andExpect(status().isBadRequest());        }        @Test        void shouldFailWithMissingImageParameter() throws Exception {            // Arrange            mockMvc = MockMvcBuilders.standaloneSetup(bookController).build();            // Act & Assert            mockMvc.perform(multipart("/addBook")                    .param("name", "Test Book"))                    .andExpect(status().isBadRequest());        }    }}

结论

这些是一些简单的测试用例,供您开始测试您的应用程序。请记住,我们可以通过添加一些工厂来重构这些测试以避免重复。

感谢您的阅读。

参考

junit5 – 文档
mockito – 文档

以上就是使用 JUnitnd Mockito 对图像上传器 API 进行单元测试的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/500745.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月8日 20:16:12
下一篇 2025年11月8日 20:17:21

相关推荐

  • linux上安装docker容器和mysql镜像拉取的方法

    docker pull xxxx 拉取镜像 docker run -it xxxx /bin/bash 启动镜像 启动docker服务 docker ps 查询运行中的容器 docker ps -a 查询所有容器,包括未运行的 mysql容器启动:docker run -itd –nam…

    数据库 2025年12月5日
    000
  • OPPO K12 非官方渲染图曝光 后置三摄 颜值有点东西

    k 系列一直是 oppo 侧重性价比的产品线,主打线上市场,有着不错的口碑。3 月 12 日下午,cnmo 注意到,有数码博主临摹出来了 2 张 oppo k12 的猜想图,设计让人眼前一亮。不过,该博主表示,” 主要是画着好玩,如果蒙对,纯属巧合。” OPPO K12 非官…

    2025年12月5日
    100
  • 新模型阐释磁性材料“半冰半火”相态

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 布鲁克海文国家实验室近期发布消息,物理学家在研究一维亚铁磁材料模型时,发现并阐释了一种前所未见的“半冰半火”物质新相态,相关成果发表在《物理评论快报》。这一发现填补了凝聚态物理学领域的认知空白,…

    2025年12月5日
    000
  • 怎么新建Python文件VSCode_VSCode创建Python文件教程

    答案:在VS Code中新建Python文件需打开软件后创建新文件并保存为.py格式,系统将自动启用Python语言服务。可通过快捷键Ctrl+N(Cmd+N)新建文件,再用Ctrl+S(Cmd+S)保存为.py文件以激活语法高亮和代码补全功能;也可通过菜单栏或资源管理器新建文件。为确保正常运行,需…

    2025年12月5日
    000
  • 如何用Docker搭建外部可以访问的mysql

    安装mysql 8.0 docker run -p 63306:3306 -e mysql_root_password=zhaooleemysql –name zhaooleemysqldb -d mysql:8.0 p 53306:3306 将docker容器的3306端口映射到宿主机的6330…

    2025年12月5日 数据库
    000
  • PHP一键环境与Docker容器化有什么区别_技术异同分析

    PHP一键环境与Docker本质区别在于封装与隔离方式:前者将服务直接安装于系统,多项目共用环境易冲突,适合新手和简单项目;后者通过容器镜像打包应用及依赖,实现环境隔离与一致,便于迁移和团队协作;一键环境部署直观但可移植性差,Docker学习成本高却支持自动化部署;资源上前者更轻量,后者虽有损耗但利…

    2025年12月5日
    000
  • DevDocs— 开源的技术文档爬取和处理工具

    devdocs:程序员和ai开发者的效率利器 DevDocs是一款开源的技术文档爬取与处理工具,专为程序员和AI开发者打造。它利用智能爬虫技术,高效地收集和整理技术文档,将原本需要数周才能完成的任务缩短至数小时。DevDocs支持多线程爬取,速度快,并能自动识别和处理网站链接,支持1-5层深度爬取。…

    2025年12月5日
    000
  • Composer如何降级一个包的版本_回滚到旧版依赖的操作方法

    要回滚Composer包版本,需修改composer.json中对应包的版本约束,执行composer update vendor/package进行降级。直接修改可能因依赖冲突失败,因Composer需确保整体依赖兼容。常见问题包括API不兼容、配置变更、传递性依赖冲突及缓存问题,可用compos…

    2025年12月5日
    000
  • VSCode怎么更改鼠标颜色_VSCode自定义鼠标指针颜色与光标样式设置教程

    VSCode无法更改系统鼠标指针颜色,但可自定义编辑器内文本光标样式、颜色及行为。通过修改settings.json文件,可设置光标样式(如line、block、underline)、宽度、闪烁方式(如blink、smooth、solid)、颜色(via workbench.colorCustomi…

    2025年12月5日
    000
  • OPPO K12 正式发布 充电五分钟通话十小时 售 1799 元起

    4月24日14点30分,oppo召开新品发布会,推出了旗下新机——oppo k12。新机提供8gb+256gb、12gb+256gb以及12gb+512gb三个版本供用户选择,售价分别为1799元、1999元、2499元。 根据官方介绍,OPPO K12 在抗摔防护上下了不少功夫。其四角采用独特的抬…

    2025年12月5日 硬件教程
    000
  • 如何在Laravel中配置队列工作器

    在laravel中配置队列工作器的核心步骤是设置队列驱动并启动监听进程,以提升应用性能和用户体验。1. 修改.env文件中的queue_connection变量,如设为redis以启用高性能队列;2. 配置redis连接信息确保其可用性;3. 使用php artisan queue:work命令启动…

    2025年12月5日
    100
  • js如何实现水印效果 前端动态生成防泄密水印

    在javascript中实现水印效果主要有canvas水印和dom水印两种方式。1. canvas水印通过创建canvas元素并使用filltext()方法绘制文字,性能较好且不易被移除,但实现较复杂;2. dom水印则通过创建div元素设置样式来显示水印,更加灵活易控,但容易被用户修改或移除。动态…

    2025年12月5日 web前端
    000
  • 如何使用docker开启mysql的binlog日志解决数据卷问题

    前言 在开发中,需要通过监听mysql的binlog日志文件做到对数据表的监控,由于mysql是部署在docker容器中,还需要解决数据卷的问题 1、通过数据卷的方式开启一个mysql镜像 docker run -p 3307:3306 –name myMysql -v /usr/docker/m…

    2025年12月5日 数据库
    000
  • VSCode怎么安装语言环境_VSCode多语言包安装与设置教程

    安装VSCode语言包需打开扩展面板搜索并安装目标语言包,如“Chinese (Simplified)”。2. 通过命令面板输入“Configure Display Language”选择语言并重启生效。3. 切换回英文界面同样操作,选择“en”或“en-US”后重启。4. 语言包不生效时检查是否重…

    2025年12月5日
    000
  • Win7电脑桌面图标如何随意放置?

    摘要:每个人都希望自己的电脑桌面整洁有序,但有时候图标却会乱糟糟地排列在一起,让人头疼不已。本文将介绍一种简单又有趣的方法,让你的Win7电脑桌面图标随意放置,让你的桌面焕然一新。 一、所需工具: 除了一台装有Win7系统的电脑外,你还需要一颗勇气和一点点耐心。 二、解决方法: 首先,右键点击桌面空…

    2025年12月5日
    100
  • java中的import怎么用 import导入类的2种高效方式

    import关键字简化类名使用,避免全限定名重复书写。其核心作用是管理命名空间,解决类名冲突。两种高效导入方式:1. 显式导入明确指定类,提升可读性;2. 通配符导入方便批量引入,但可能降低可读性。此外,静态导入用于直接使用静态成员。import仅在编译时提供类信息,并不触发类加载。处理同名类时需手…

    2025年12月5日 java
    000
  • PHP连接Redis时如何实现数据缓存的详细步骤?

    php连接redis做数据缓存的关键在于环境搭建和正确使用redis扩展。1.安装redis服务并启动,确保运行在默认端口6379;2.安装php-redis扩展,ubuntu/debian用sudo apt-get install php-redis,centos用sudo yum install…

    2025年12月5日 后端开发
    000
  • Node.js如何处理环境变量?

    node.js通过process.env对象处理环境变量,允许访问和设置。使用方式包括命令行临时设置、.env文件配合dotenv库加载、dockerfile、kubernetes configmap/secret及云平台配置;1. 通过node_env加载不同配置文件实现多环境支持;2. 敏感信息…

    2025年12月5日 web前端
    000
  • VSCode欢迎页面怎么打开_VSCode恢复欢迎界面教程

    答案:通过“帮助”菜单或命令面板可打开VSCode欢迎页面,若启动时不显示,需将workbench.startupEditor设置为welcomePage。该页面提供快速启动、学习资源、个性化设置等功能,支持根据习惯选择启动时显示内容,如上次会话、空白文件等,便于高效使用编辑器。 在VSCode里打…

    2025年12月5日
    000
  • composer anaconda环境冲突怎么办_解决Composer与Anaconda环境冲突的方案

    优先隔离环境变量或使用Docker容器可解决Composer与Anaconda冲突。具体步骤:1. 临时修改PATH,移除Anaconda路径,仅保留PHP和Composer所需路径;2. 创建独立快捷方式分别启动PHP/Composer和Anaconda环境;3. 使用Docker运行PHP容器,…

    2025年12月5日
    000

发表回复

登录后才能评论
关注微信