SpringBoot使用MockMVC单元测试Controller

news2024/10/7 18:29:58

前言:

     在SpringBoot应用程序中,Controller是接受客户端请求并返回响应数据的核心组件。为了保证Controller的正确性和稳定性,我们可以使用MockMVC框架进行单元测试。MockMVC是Spring框架提供的一个HTTP客户端,用于模拟HTTP请求和响应,以测试Controller的行为和逻辑。使用MockMVC,我们可以在不启动应用程序的情况下对Controller进行测试,这样可以提高测试效率和方便测试调试。在测试Controller时,我们通常使用mock方法模拟Service和Repository的行为,以隔离Controller和其他组件的依赖关系。同时,我们还可以使用Hamcrest和AssertJ等断言库对结果进行断言,以验证Controller的行为是否符合预期。

       MockMvcBuilder是用来构造MockMvc的构造器,其主要有两个实现:StandaloneMockMvcBuilder和DefaultMockMvcBuilder,分别对应两种测试方式,即独立安装和集成Web环境测试(此种方式并不会集成真正的web环境,而是通过相应的Mock API进行模拟测试,无须启动服务器)。对于我们来说直接使用静态工厂MockMvcBuilders创建即可。

       下面就写一个简单的案例,告诉你是如何使用MockMvc进行Controller测试的

       第一步、创建项目

       创建一个Maven项目(springboot-junit),并配置pom.xml,参照下面代码

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.lvgang</groupId>
  <artifactId>springboot-junit</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>springboot-junit</name>
  <url>http://maven.apache.org</url>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.3.RELEASE</version>
  </parent>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
  </dependencies>
</project>
创建一个Controller类,我们在后面就测试空上Controller
package org.lvgang;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
    @RequestMapping("/")
    public String hello(String name){
        return "hello "+name;
    }
}

       第二步、编写测试类

       下面我们就是编写测试类了

package org.lvgang;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
//SpringBoot1.4版本之前用的是SpringJUnit4ClassRunner.class
@RunWith(SpringRunner.class)
//SpringBoot1.4版本之前用的是@SpringApplicationConfiguration(classes = Application.class)
@SpringBootTest(classes = App.class)
//测试环境使用,用来表示测试环境使用的ApplicationContext将是WebApplicationContext类型的
@WebAppConfiguration
public class HelloControllerTest {
    @Autowired
    private WebApplicationContext webApplicationContext;
    private MockMvc mockMvc;
    @Before
    public void setUp() throws Exception{
        //MockMvcBuilders.webAppContextSetup(WebApplicationContext context):指定WebApplicationContext,将会从该上下文获取相应的控制器并得到相应的MockMvc;
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();//建议使用这种
    }
    @Test
    public void getHello() throws Exception{
        /**
         * 1、mockMvc.perform执行一个请求。
         * 2、MockMvcRequestBuilders.get("XXX")构造一个请求。
         * 3、ResultActions.param添加请求传值
         * 4、ResultActions.accept(MediaType.TEXT_HTML_VALUE))设置返回类型
         * 5、ResultActions.andExpect添加执行完成后的断言。
         * 6、ResultActions.andDo添加一个结果处理器,表示要对结果做点什么事情
         *   比如此处使用MockMvcResultHandlers.print()输出整个响应结果信息。
         * 5、ResultActions.andReturn表示执行完成后返回相应的结果。
         */
        MvcResult mvcResult= mockMvc.perform(MockMvcRequestBuilders.get("/")
                .param("name","lvgang")
                .accept(MediaType.TEXT_HTML_VALUE))
               // .andExpect(MockMvcResultMatchers.status().isOk())             //等同于Assert.assertEquals(200,status);
               // .andExpect(MockMvcResultMatchers.content().string("hello lvgang"))    //等同于 Assert.assertEquals("hello lvgang",content);
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
        int status=mvcResult.getResponse().getStatus();                 //得到返回代码
        String content=mvcResult.getResponse().getContentAsString();    //得到返回结果
        Assert.assertEquals(200,status);                        //断言,判断返回代码是否正确
        Assert.assertEquals("hello lvgang",content);            //断言,判断返回的值是否正确
    }
}

       整个测试过程如下:

  1. 准备测试环境

  2. 通过MockMvc执行请求

  3. 添加验证断言

  4. 添加结果处理器

  5. 得到MvcResult进行自定义断言/进行下一步的异步请求

  6. 卸载测试环境

       第三步、测试结果

       通过执行HelloControllerTest,得到以下结果:

       并且把整个返回结果都打印到了Console中

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /
       Parameters = {name=[lvgang]}
          Headers = {Accept=[text/html]}
Handler:
             Type = org.lvgang.HelloController
           Method = public java.lang.String org.lvgang.HelloController.hello(java.lang.String)
Async:
    Async started = false
     Async result = null
Resolved Exception:
             Type = null
ModelAndView:
        View name = null
             View = null
            Model = null
FlashMap:
       Attributes = null
MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = {Content-Type=[text/html;charset=UTF-8], Content-Length=[12]}
     Content type = text/html;charset=UTF-8
             Body = hello lvgang
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

 

       通过以上代码,我们就完成了一个简单的案例。

       附:

       RequestBuilder/MockMvcRequestBuilders:

       在上面的测试类中,我们用到了这么一个类MockMvcRequestBuilders用来构建请求的,此类有以下主要的API:

MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables):根据uri模板和uri变量值得到一个GET请求方式的MockHttpServletRequestBuilder;如get(/user/{id}, 1L);
MockHttpServletRequestBuilder post(String urlTemplate, Object... urlVariables):同get类似,但是是POST方法;
MockHttpServletRequestBuilder put(String urlTemplate, Object... urlVariables):同get类似,但是是PUT方法;
MockHttpServletRequestBuilder delete(String urlTemplate, Object... urlVariables) :同get类似,但是是DELETE方法;
MockHttpServletRequestBuilder options(String urlTemplate, Object... urlVariables):同get类似,但是是OPTIONS方法;
MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVariables): 提供自己的Http请求方法及uri模板和uri变量,如上API都是委托给这个API;
MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object... urlVariables):提供文件上传方式的请求,得到MockMultipartHttpServletRequestBuilder;
RequestBuilder asyncDispatch(final MvcResult mvcResult):创建一个从启动异步处理的请求的MvcResult进行异步分派的RequestBuilder;

       MockMvcRequestBuilders通过方法得到两类Builder,一个是MockHttpServletRequestBuilder ,一个是MockMultipartHttpServletRequestBuilder (上传文件)

       MockHttpServletRequestBuilder:

       MockHttpServletRequestBuilder 主要有一下API:

MockHttpServletRequestBuilder header(String name, Object... values)/MockHttpServletRequestBuilder headers(HttpHeaders httpHeaders):添加头信息;
MockHttpServletRequestBuilder contentType(MediaType mediaType):指定请求的contentType头信息;
MockHttpServletRequestBuilder accept(MediaType... mediaTypes)/MockHttpServletRequestBuilder accept(String... mediaTypes):指定请求的Accept头信息;
MockHttpServletRequestBuilder content(byte[] content)/MockHttpServletRequestBuilder content(String content):指定请求Body体内容;
MockHttpServletRequestBuilder param(String name,String... values):请求传入参数
MockHttpServletRequestBuilder cookie(Cookie... cookies):指定请求的Cookie;
MockHttpServletRequestBuilder locale(Locale locale):指定请求的Locale;
MockHttpServletRequestBuilder characterEncoding(String encoding):指定请求字符编码;
MockHttpServletRequestBuilder requestAttr(String name, Object value) :设置请求属性数据;
MockHttpServletRequestBuilder sessionAttr(String name, Object value)/MockHttpServletRequestBuilder sessionAttrs(Map<string, object=""> sessionAttributes):设置请求session属性数据;
MockHttpServletRequestBuilder flashAttr(String name, Object value)/MockHttpServletRequestBuilder flashAttrs(Map<string, object=""> flashAttributes):指定请求的flash信息,比如重定向后的属性信息;
MockHttpServletRequestBuilder session(MockHttpSession session) :指定请求的Session;
MockHttpServletRequestBuilder principal(Principal principal) :指定请求的Principal;
MockHttpServletRequestBuilder contextPath(String contextPath) :指定请求的上下文路径,必须以“/”开头,且不能以“/”结尾;
MockHttpServletRequestBuilder pathInfo(String pathInfo) :请求的路径信息,必须以“/”开头;
MockHttpServletRequestBuilder secure(boolean secure):请求是否使用安全通道;
MockHttpServletRequestBuilder with(RequestPostProcessor postProcessor):请求的后处理器,用于自定义一些请求处理的扩展点;

       MockMultipartHttpServletRequestBuilder:

       MockMultipartHttpServletRequestBuilder继承自MockHttpServletRequestBuilder,又提供了如下API:

MockMultipartHttpServletRequestBuilder file(String name, byte[] content)/MockMultipartHttpServletRequestBuilder file(MockMultipartFile file):指定要上传的文件;

       ResultActions:

       调用MockMvc.perform(RequestBuilder requestBuilder)后将得到ResultActions,通过ResultActions完成如下三件事:

ResultActions andExpect(ResultMatcher matcher) :添加验证断言来判断执行请求后的结果是否是预期的;
ResultActions andDo(ResultHandler handler) :添加结果处理器,用于对验证成功后执行的动作,如输出下请求/结果信息用于调试;
MvcResult andReturn() :返回验证成功后的MvcResult;用于自定义验证/下一步的异步处理;

       ResultMatcher/MockMvcResultMatchers:

       ResultMatcher用来匹配执行完请求后的结果验证,其就一个match(MvcResult result)断言方法,如果匹配失败将抛出相应的异常;此类案例中并为使用,请自行查看。具体提供以下API:

HandlerResultMatchers handler():请求的Handler验证器,比如验证处理器类型/方法名;此处的Handler其实就是处理请求的控制器;
RequestResultMatchers request():得到RequestResultMatchers验证器;
ModelResultMatchers model():得到模型验证器;
ViewResultMatchers view():得到视图验证器;
FlashAttributeResultMatchers flash():得到Flash属性验证;
StatusResultMatchers status():得到响应状态验证器;
HeaderResultMatchers header():得到响应Header验证器;
CookieResultMatchers cookie():得到响应Cookie验证器;
ContentResultMatchers content():得到响应内容验证器;
JsonPathResultMatchers jsonPath(String expression, Object ... args)/ResultMatcher jsonPath(String expression, Matcher matcher):得到Json表达式验证器;
XpathResultMatchers xpath(String expression, Object... args)/XpathResultMatchers xpath(String expression, Map<string, string=""> namespaces, Object... args):得到Xpath表达式验证器;
ResultMatcher forwardedUrl(final String expectedUrl):验证处理完请求后转发的url(绝对匹配);
ResultMatcher forwardedUrlPattern(final String urlPattern):验证处理完请求后转发的url(Ant风格模式匹配,@since spring4);
ResultMatcher redirectedUrl(final String expectedUrl):验证处理完请求后重定向的url(绝对匹配);
ResultMatcher redirectedUrlPattern(final String expectedUrl):验证处理完请求后重定向的url(Ant风格模式匹配,@since spring4);

 作为一位过来人也是希望大家少走一些弯路,希望能对你带来帮助。(WEB自动化测试、app自动化测试、接口自动化测试、持续集成、自动化测试开发、大厂面试真题、简历模板等等),相信能使你更好的进步!

留【自动化测试】即可【自动化测试交流】:574737577(备注ccc)icon-default.png?t=N5F7http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=hyGITtX0cD6EN96WzR_d5b1qRSZ-Dpyy&authKey=76TmCzaAQ%2BOwLn6umFFZeVxKheSwyaUVwymd%2FRvdARY6cvCSCgZ1qOSe3w%2Bsh61f&noverify=0&group_code=574737577

 

 

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

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

相关文章

2023年智能优化算法之——增长优化器Growth Optimizer(GO),附MATLAB代码

增长优化器的主要设计灵感来源于个人在社会成长过程中的学习和反思机制。学习是个体通过从外部世界获得知识而成长的过程。反思是检查个人自身不足并调整个人学习策略以帮助个人成长的过程。参考文献如下&#xff1a; Zhang, Qingke, et al. “Growth Optimizer: A Powerful M…

二维码在固定资产实物盘点中的应用

很多企业为了掌握固定资产的后续使用情况和状态&#xff0c;会定期对投入使用的固定资产进行盘点&#xff0c;然而固定资产常会出现分散情况&#xff0c;在这种情况下让财务人员到达每个固定资产的所在处进行实地盘点显得极为不现实。 也有不少企业会在盘点过程中使用到固定资…

聊天室(一)___常见的基本功能实现

最近搞聊天室的人还挺多&#xff0c;正好自己也弄就总结自己遇到必不可少的一些功能&#xff0c;本篇文章主要为自己和看到我文章的人一种思路&#xff0c;希望大家不要把聊天室想的太复杂。 上图是我自己做的一个聊天室&#xff0c;类似微信的单聊群聊收藏等功能&#xff0c;根…

python+requests接口自动化框架详解,没有比这个更详细的了

目录 为什么要做接口自动化框架 正常接口测试的流程是什么&#xff1f; 一、接口框架如下&#xff1a; 二、接口的数据规范设计---Case设计 2.1注册接口用例 2.2登录接口用例 三、创建utils包&#xff1a;用来存放公共的类 3.1 ParseExcel.py 操作封装excel的类&#xf…

【AI工具】-Stable Diffusion本地化部署教程

前言 今天我们要介绍的是时下最流行的AI绘图软件Stable Diffusion&#xff0c;虽然Diffusion.ai已经开放api&#xff0c;但是长时间的商业化调用我们需要购买很多的金币。所以我们需要找一个平替的AI绘图平台&#xff0c;现在主流市场中AI绘图软件主要就是OpenAI的DALLE、midj…

SSM会议管理系统

SSM会议管理系统 后端基于SSM、前端基于Freemarker写的会议管理系统、使用JDK8、mysql使用5.7版本 技术栈 Spring SpringMVC MyBatis Mysql Freemarker jqueryajax[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JGo0luHu-1687163482019)(img.png)] …

【Python 随练】打印水仙花数

题目&#xff1a; 打印出所有的"水仙花数"&#xff0c;所谓"水仙花数"是指一个三位数&#xff0c;其各位数字立方和等于该数 简介&#xff1a; 在本篇博客中&#xff0c;我们将解决一个经典的数学问题&#xff1a;打印出所有的水仙花数。水仙花数是指一…

Unity核心5——Tilemap

Tilemap 一般称之为瓦片地图或者平铺地图&#xff0c;是 Unity2017 中新增的功能&#xff0c;主要用于快速编辑 2D 游戏中的场景&#xff0c;通过复用资源的形式提升地图多样性 ​ 工作原理就是用一张张的小图排列组合为一张大地图 ​ 它和 SpriteShape 的异同 共同点&#x…

浅析GPT2中的autoregressive和BERT的autoencoding源码实现

经常使用BERT来做研究&#xff0c;因此对Encoder的架构较为熟悉&#xff0c;但是从来没有了解过GPT这样的Decoder架构&#xff0c;尤其对自回归的形式不知道源码是如何实现的。 为了方便对比和讨论&#xff0c;接来下所探讨的源码都是基于HuggingFace这个框架的。 Bert注意力…

基于亚马逊云科技Serverless,朝夕光年和Second Dinner携手打造年度手游

经典的漫威IP&#xff0c;酷炫的卡牌对战&#xff0c;丰富的故事情节&#xff0c;这款移动游戏《MARVEL SNAP》一经上线就深得全球玩家喜爱。在The Game Awards 2022的年度颁奖典礼上&#xff0c;它更是以出色的表现&#xff0c;一举斩获最佳移动游戏奖项。 其研发公司Second …

【ElasticSearch】中文分词器

ES默认的analyzer&#xff08;分词器&#xff09;&#xff0c;对英文单词比较友好&#xff0c;对中文分词效果不好。不过ES支持安装分词插件&#xff0c;增加新的分词器。 1、如何指定analyzer&#xff1f; 默认的分词器不满足需要&#xff0c;可以在定义索引映射的时候&#…

Python自动办公之合并多个PDF文件

本文基于使用pycharm平台&#xff0c;使用glob库和PyPDF2库实现 首先将需要合并的文件放于一个文件中 如下图 addpdf文件夹为需要合并的文件位置 good.py为代码块 代码如下 print(这个小代码仅仅用于合并pdf文件数量小于10的情况) print() from PyPDF2 import PdfMerger,P…

深度解析DuckDB的ScheduleEvents

深度解析DuckDB的ScheduleEvents 1.ScheduleEventData2.ScheduleEventsInternal3.SchedulePipeline 3.1 Event3.2 PipelineEventStack3.3 主逻辑4.可视化总结 书接上回熬夜三晚之深度解析DuckDB MetaPipeline&#xff0c;MetaPipeline在初始化的时候会构建出下面几个&#xff1…

【ARMv8/v9 异常模型入门及渐进2 - 系统控制寄存器 SCTRL_ELx 介绍】

文章目录 SCTRL_ELx 介绍背景ARMv8 SCTLR_ELx 介绍ARMv9 SCTLR_ELx 介绍 SCTRL_ELx 介绍背景 由于在做DFD 测试过程中需要测试 EL1 状态下的 self-hosted trace 功能&#xff0c;但是这个测试是在UEFI中做的&#xff0c;在开发验证阶段UEFI默认是运行在EL3 下的&#xff0c;所…

mac安装VsCode遇到的问题

万事开头难&#xff0c;头一次在安装生产工具的时候&#xff0c;就遇到了这么棘手的问题。百度和Google都试过了&#xff0c;网上的所有方式对我都没效果。最终自己阴差阳错解决了&#xff0c;我看内外网反馈这个问题的还挺多&#xff0c;在这里记录一下&#xff0c;希望可以帮…

Docker专题系列之十三:docker容器内安装vim编辑器

在使用docker时&#xff0c;有时候我们需要编辑配置文件&#xff0c;需要使用vim或者vi命令&#xff0c;但是会发现&#xff1a; root20ab69bedcdb:/etc/mysql# vim my.cnf bash: vim: command not found这是因为vim没有安装&#xff0c;使用如下命令安装&#xff1a; apt-ge…

Tomcat架构设计

Servlet规范 Servlet是JavaEE规范中的一种&#xff0c;主要是为了扩展Java作为Web服务的功能&#xff0c;统一定义了对应的接口&#xff0c;如Servlet接口&#xff0c;HttpRequest接口&#xff0c;HttpResponse接口&#xff0c;Filter接口。然后由具体的服务厂商来实现这些接口…

adroit java反编译

环境准备 靶机链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;4e5y 虚拟机网络链接模式&#xff1a;桥接模式 攻击机系统&#xff1a;kali linux 2021.1 信息收集 1.探测目标靶机ip地址 arp-scan -l 2.用nmap探测靶机开放端口和服务情况 nmap -p- -A -T4 19…

二分类结局变量Logistic回归临床模型预测—— 模型评价(一)

本节讲的是二分类结局变量的临床模型预测,与之前讲的Cox回归不同,https://lijingxian19961016.blog.csdn.net/article/details/124088364https://lijingxian19961016.blog.csdn.net/article/details/124088364https://lijingxian19961016.blog.csdn.net/article/details/1240…

基于springboot+Redis的前后端分离项目(二)-【黑马点评】

&#x1f381;&#x1f381;资源文件分享 链接&#xff1a;https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA?pwdeh11 提取码&#xff1a;eh11 商户查询缓存&#xff0c;缓存更新策略&#xff0c;缓存穿透 商户查询缓存a.什么是缓存1.为什么要使用缓存2.如何使用缓存 b.添加商…