mockMvc测试
2022/1/20 23:14:16
本文主要是介绍mockMvc测试,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1.环境准备
本文主要是介绍mock测试方面的知识,用到的环境是 idea + jdk8 + mysql5.5.49 + Junit5 + springBoot 2.6 + mokito
1.1数据库脚本准备
-- 创建订单表 CREATE TABLE `sale_order` ( `id` bigint NOT null AUTO_INCREMENT COMMENT '客户订单ID', `sale_order_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '订单编号', `customer` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '客户', PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `uni_sale_order_code` (`sale_order_code`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='客户订单(销售订单)'; -- 创建订单颜色明细表 CREATE TABLE `sale_order_detail` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '客户订单明细ID', `sale_order_id` bigint NOT NULL COMMENT '客户订单ID', `color` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, `quantity` bigint DEFAULT NULL COMMENT '数量', `receiver_price` decimal(22,2) DEFAULT NULL COMMENT '接单价格', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='客户订单明细表(下单信息)';
1.2.pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.fufulong.demo</groupId> <artifactId>mock-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>mock-demo</name> <description>mock-demo</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.6.5</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-core --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.12.4</version> <scope>test</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.75</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.yml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>META-INF/**</include> <include>template/*</include> </includes> <filtering>false</filtering> </resource> </resources> </build> </project>
1.3 配置文件准备
spring: application: name: mock-demo datasource: username: root password: xxxx url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&rewriteBatchedStatements=true servlet: multipart: max-request-size: 100MB max-file-size: 10MB server: port: 9000 servlet: context-path: /mock-demo
2. mockMvc 的使用方法
2.1 初始化mockMvc
使用@SpringBootTest
注解会加载整个Context。这样我们可以自动获得所有在Context中注入的Bean,以及从application.properties中加载的配置信息。
在@SpringBootTest
中声明webEnvironment为WebEnvironment.MOCK
(默认值就是WebEnvironment.MOCK
)后,结合@AutoConfigureMockMvc
注解,在测试的时候会得到一个模拟的Web/Servlet环境。
因为没有Web Server,所以就无法使用RestTemplate
,也就只能继续使用MockMVC
了。这次MockMVC
的实例是由@AutoConfigureMockMvc
注解来完成的。这归功于SpringBoot的自动化配置。
junit5和junit4环境,初始化mocKMvc的方法不一样,如果是Junit5,初始化 mockMvc的代码如下:
@SpringBootTest(classes = MockDemoApplication.class) @AutoConfigureMockMvc class MockDemoApplicationTests { @Autowired private MockMvc mockMvc; }
也可以使用另外一种方式,使用MockMvcBuilders 得静态方法初始化mockMvc,这样做还可以设置每次mock测试都要执行的动作,期望等
@SpringBootTest(classes = MockDemoApplication.class) class MockDemoApplicationTests { private MockMvc mockMvc; @Autowired private WebApplicationContext webApplicationContext; @BeforeEach public void setUp(){ // 设定mockMvc能mock的controller是整个springBoot项目环境中的controller mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext). build(); } }
2.2 测试post类型的接口
接口方法
@RestController @RequestMapping("saleOrder") public class SaleOrderController { @Autowired private SaleOrderService saleOrderService; @PostMapping(value = "/save") public DataResponse<Long> save(@RequestBody SaveSaleOrderReq req){ Long id = saleOrderService.save(req); return DataResponse.ok(id); } }
测试方法
@Test public void test1() throws Exception { SaleOrder saveOrder = new SaleOrder(); saveOrder.setSaleOrderCode("0001"); saveOrder.setCustomer("小明"); MockHttpServletRequestBuilder requestBuilder = //请求路径,不需要带前面 servletContext部分 MockMvcRequestBuilders.post("/saleOrder/save") // post请求返回的mediaType .accept(MediaType.APPLICATION_JSON) // post请求的请求内容的 mediaType .contentType(MediaType.APPLICATION_JSON) // post 请求参数内容 .content(JSON.toJSONString(saveOrder)); MvcResult mvcResult = mockMvc.perform(requestBuilder) // 设置期望的结果,用 ResultMatcher 来表示 .andExpect(MockMvcResultMatchers.status().isOk()) // 内置的打印mock请求结果 .andDo(MockMvcResultHandlers.print()) // 正式执行接口,并返回接口的返回值 .andReturn(); // 把 mvcResult 的 response对象,转换成 json,然后打印显示 String s = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); System.out.println(s); }
结果如下所示:
MockHttpServletRequest: HTTP Method = POST Request URI = /saleOrder/save Parameters = {} Headers = [Content-Type:"application/json", Accept:"application/json", Content-Length:"44"] Body = <no character encoding set> Session Attrs = {} Handler: Type = com.fufulong.demo.mockdemo.controller.SaleOrderController Method = com.fufulong.demo.mockdemo.controller.SaleOrderController#save(SaveSaleOrderReq) 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:"application/json"] Content type = application/json Body = {"successful":true,"code":"200","message":null,"data":1} Forwarded URL = null Redirected URL = null Cookies = [] {"successful":true,"code":"200","message":null,"data":1}
2.3 测试get类型的接口 (requestParam参数类型)
接口方法
@GetMapping(value = "/get-one") public DataResponse<SaleOrder> getOne(@RequestParam(value = "saleOrderId") Long saleOrderId){ SaleOrder saleOrder = saleOrderService.selectOne(saleOrderId); return DataResponse.ok(saleOrder); }
测试方法
@Test public void test2() throws Exception { MockHttpServletRequestBuilder requestBuilder = //请求路径,不需要带前面 servletContext部分 MockMvcRequestBuilders.get("/saleOrder/get-one") // 设置请求参数 .param("saleOrderId","1"); MvcResult mvcResult = mockMvc.perform(requestBuilder) // 设置期望的结果,用 ResultMatcher 来表示 .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()) .andReturn(); String s = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); System.out.println(s); }
测试结果输出
MockHttpServletRequest: HTTP Method = GET Request URI = /saleOrder/get-one Parameters = {saleOrderId=[1]} Headers = [] Body = <no character encoding set> Session Attrs = {} Handler: Type = com.fufulong.demo.mockdemo.controller.SaleOrderController Method = com.fufulong.demo.mockdemo.controller.SaleOrderController#getOne(Long) 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:"application/json"] Content type = application/json Body = {"successful":true,"code":"200","message":null,"data":{"id":1,"saleOrderCode":"0001","customer":"å°æ˜Ž"}} Forwarded URL = null Redirected URL = null Cookies = [] {"successful":true,"code":"200","message":null,"data":{"id":1,"saleOrderCode":"0001","customer":"小明"}}
2.4 测试get类型的接口 (path参数类型)
接口代码
@GetMapping(value = "/get-one/{saleOrderCode}/{id}") public DataResponse<SaleOrder> getOneByCode(@PathVariable(value = "saleOrderCode") String saleOrderCode, @PathVariable(value = "id") Long id ){ SaleOrder saleOrder = saleOrderService.getOneByCode(saleOrderCode,id); return DataResponse.ok(saleOrder); }
测试方法
@Test public void test3() throws Exception { String saleOrderCode = "0001"; Long id = 1L; MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/saleOrder/get-one/{saleOrderCode}/{id}",saleOrderCode,id); MvcResult mvcResult = mockMvc.perform(requestBuilder) // 设置期望的结果,用 ResultMatcher 来表示 .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()) .andReturn(); String s = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); System.out.println(s); }
测试结果打印
MockHttpServletRequest: HTTP Method = GET Request URI = /saleOrder/get-one/0001/1 Parameters = {} Headers = [] Body = <no character encoding set> Session Attrs = {} Handler: Type = com.fufulong.demo.mockdemo.controller.SaleOrderController Method = com.fufulong.demo.mockdemo.controller.SaleOrderController#getOneByCode(String, Long) 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:"application/json"] Content type = application/json Body = {"successful":true,"code":"200","message":null,"data":{"id":1,"saleOrderCode":"0001","customer":"å°æ˜Ž"}} Forwarded URL = null Redirected URL = null Cookies = [] {"successful":true,"code":"200","message":null,"data":{"id":1,"saleOrderCode":"0001","customer":"小明"}}
2.5 测试上传文件
接口代码
@RequestMapping(value = "/uploadFile") public DataResponse<Void> uploadFile(@RequestParam(value = "file") MultipartFile file) throws IOException { InputStream inputStream = null; OutputStream outputStream = null; try{ inputStream = file.getInputStream(); outputStream = FileUtil.getOutputStream(new File(Objects.requireNonNull(file.getOriginalFilename()))); IoUtil.copy(inputStream,outputStream); }finally { if (inputStream != null){ inputStream.close(); } if (outputStream != null){ outputStream.close(); } } return DataResponse.ok(); }
测试代码
@Test public void test4() throws Exception { File file = new File("C:\\Users\\付福龙\\Desktop\\兔子.jpeg"); MockMultipartFile uploadFile = new MockMultipartFile("file", "兔子.jpeg", MediaType.IMAGE_JPEG_VALUE, new FileInputStream(file)); MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.multipart("/saleOrder/uploadFile").file(uploadFile).contentType( MediaType.IMAGE_JPEG); MvcResult mvcResult = mockMvc.perform(requestBuilder) // 设置期望的结果,用 ResultMatcher 来表示 .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()) .andReturn(); }
测试结果
MockHttpServletRequest: HTTP Method = POST Request URI = /saleOrder/uploadFile Parameters = {} Headers = [Content-Type:"image/jpeg"] Body = <no character encoding set> Session Attrs = {} Handler: Type = com.fufulong.demo.mockdemo.controller.SaleOrderController Method = com.fufulong.demo.mockdemo.controller.SaleOrderController#uploadFile(MultipartFile) 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:"application/json"] Content type = application/json Body = {"successful":true,"code":"200","message":null,"data":null} Forwarded URL = null Redirected URL = null Cookies = []
3.mockMvc测试controller总结
- 先有业务接口方法
- 新建的测试类中,需要先初始化mockMvc对象
- 根据接口方法的类型不同(post/get/multipart等),选择构建不同的MockHttpServletRequestBuilder 对象, 在这里设置请求地址,注意地址是不需要 地址端口和servletContextpath前缀的,且需要注意用"/"开头. 然后设置 queryParam或者pathParam或者 content,还可以设置请求头等
- 调用mockMvc的方法,指定需要执行的请求, mockMvc.perform(MockHttpServletRequestBuilder )
- 然后设置断言,断言可以设置多个,使用方法 andExpect(ResultMatcher matcher) 设置, MockMvcResultMatchers中有许多常用的断言结果匹配器,可以使用
- 然后设置结果处理方法, 使用方法 ResultActions andDo(ResultHandler handler) 来处理,同样 MockMvcResultHandlers 总有需要封装好的静态方法可以用
- 然后 调用方法 MvcResult andReturn() ,此时才会真的执行接口, 得到 MvcResult 结果
- 可以使用 mvcResult.getResponse() 得到 MockHttpServletResponse 对象, 这个对象有许多请求结果的信息,比如状态,内容等, 可以根据这些内容写后续的验证代码
4. mockMvc测试重要API
41. MockMvcRequestBuilders
- MockMvcRequestBuildersMockHttpServletRequestBuilder get(String urlTemplate, Object… uriVars)
构建 get请求,设置请求地址,并且可以设置路径参数,注意如果要设置路径参数,参数值和类型必须要对应地址中参数名 - MockHttpServletRequestBuilder post(String urlTemplate, Object… uriVars)
构建 post 请求, 设置请求地址, post方法虽然也可以设置 pathParam和queryParam,但是不建议这样做. - MockMultipartHttpServletRequestBuilder multipart(String urlTemplate, Object… uriVars)
构建 上传文件 请求, 设置上传文件的接口地址和路径参数等.
4.2 MockMvcRequestBuilder
-
MockHttpServletRequestBuilder param(String name, String… values)
向请求参数map中添加非path类型的参数,也就是设置 queryParam的方法
-
MockHttpServletRequestBuilder header(String name, Object… values)
向请求头map中添加请求头键值对 -
MockHttpServletRequestBuilder contentType(MediaType contentType)
设置接口的参数内容的 contentType,如果业务接口是 @requestController 修饰的, contentType 一般是MediaType.APPLICATION_JSON -
MockHttpServletRequestBuilder accept(MediaType… mediaTypes)
设置接口的可以接收的返回数据的MediaType, 如果业务接口是 @requestController 修饰的, 一般是MediaType.APPLICATION_JSON -
MockHttpServletRequestBuilder content(String content)
设置requestBody的内容,一般是post请求的时候需要设置
4.3 ResultActions
- ResultActions andExpect(ResultMatcher matcher)
设置请求相关的断言,可以连续调用多次设置不同的断言. - ResultActions andDo(ResultHandler handler)
设置对接口返回结果的处理方式 - MvcResult andReturn()
执行测试接口,得到结果,返回数据
4.4 MockMvcResultMatchers
- StatusResultMatchers status(): 得到结果状态匹配器, 可以使用StatusResultMatchers 的方法断言请求状态,请求是否正常返回等.
- ModelResultMatchers model(): 当请求不是rest风格的时候,返回接口结果中的数据model,可用进一步通过调用 ModelResultMatchers 的静态方法,判断返回的数据中的属性的值等
- ViewResultMatchers view(): 当请求不是rest风格的时候,返回接口结果中的视图地址匹配器
- JsonPathResultMatchers jsonPath(String expression, Object… args) / ResultMatcher jsonPath(String expression, Matcher<? super T> matcher) / ResultMatcher jsonPath(String expression, Matcher<? super T> matcher, Class targetType)
当接口返回的数据是Json的形式,可以用这3个方法设置断言匹配器, 关于 jsoPath的设置,比较复杂,可以看官网地址: https://github.com/json-path/JsonPath
4.5 MockMvcResultHandlers
这里的方法主要是打印或者日志记录mock测试的主要信息,注意如果是打印到系统的控制台,使用的是系统的编码方式,如果是wIndows系统,就是ISO-8859-1,那么输出的中文就是乱码了.
4.6 MockHttpServletResponse
- String getContentAsString(Charset fallbackCharset)
把接口返回的数据内容转换成字符串形式,并指定了编码方式
这篇关于mockMvc测试的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-04el-table 开启定时器下,表格的选中状态会消失是什么原因-icode9专业技术文章分享
- 2024-10-03如何安装和初始化飞牛私有云 fnOS?-icode9专业技术文章分享
- 2024-10-03如何安装 App 并连接到飞牛 NAS?-icode9专业技术文章分享
- 2024-10-03如何安装飞牛 TV 并连接到影视服务器?-icode9专业技术文章分享
- 2024-10-03如何在PVE和ESXI上安装飞牛私有云 fnOS?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS安装系统异常情况处理-icode9专业技术文章分享
- 2024-10-03飞牛NAS如何创建存储空间?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS硬盘会自动休眠吗?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS如何安装飞牛影视和创建媒体库?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS如何为家人朋友开通影视账号?-icode9专业技术文章分享