相關歷史文章(閱讀本文前,您可能需要先看下之前的系列👇)
國內最全的Spring Boot系列之三
2020上半年發文匯總「值得收藏」
Slf4j的前世今生之java日誌框架演化歷史 - 第334篇
SpringBoot框架開發的優秀的項目「值得收藏學習」 - 第335
從Spring整合第三方框架學習Spring Boot - 第336篇
Mock工具之Mockito - 第337篇
Spring Boot中使用Mockito - 第338篇
悟纖:師傅,我上面mock的service層和dao層的例子?我看了下這個web層的,好像不行呢?是不支持嗎?
師傅:Mockito這個還是很成熟的,不支持在這裡是木有的,還是你沒研究到位。
悟纖:歐侯,是這樣子的嗎?
師傅:你這麼聰明伶俐,師傅能忽悠得了你嘛。
悟纖:也對,那我再去好好研究一下。
一、概述
在web應用程式中,對Controller層的測試一般有兩種方法:
(1)發送http請求;
(2)模擬http請求對象;
今天我們來看下如何用Mock對象測試Controller層的代碼。
二、準備工作
2.1 版本說明
(1)Spring Boot : 2.4.0
(2)Mockito:3.6.0
2.2 新建一個Controller
這裡我們是基於前面的文章《Spring Boot中使用Mockito》進行編碼。
如果對於Mockito還不了解的話,可以看《Mock工具之mockito》。
好了進入正題,我們添加web依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>然後新建一個UserController:
package com.kfit.springbootmockitodemo.demo.controller;
import com.kfit.springbootmockitodemo.demo.bean.User;import com.kfit.springbootmockitodemo.demo.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;
@RestController@RequestMapping("/user")public class UserController {
@Autowired private UserService userService;
@RequestMapping("/findById") public User findById(int id){ return userService.findById(id); }
}這代碼沒啥好講的,spring boot項目的hello代碼了,如果你連spring boot還不懂,那麼我只能…… 送你一份我的獨門秘籍了:
《國內最全的Spring Boot系列之一》
https://mp.weixin.qq.com/s/dhGgXrff-p4xcQNO3ON79A
《國內最全的Spring Boot系列之二》
https://mp.weixin.qq.com/s/kQ01ShwPQoxsBbMC4RlECA
《國內最全的Spring Boot系列之三》
https://mp.weixin.qq.com/s/wpcc86uoaZnAim6MTRAOGQ
三、Mockito使用
接下來才是本節的重點,請那個板凳認真聽。
3.1 說明
(1)@RunWith
對於web的單元測試,需要使用註解:@RunWith(SpringRunner.class),@RunWith(SpringRunner.class),這是JUnit的註解,通過這個註解讓SprignRunner這個類提供Spring測試上下文。
(2)MockMvc
MockMvc對象提供一組工具函數用來執行assert判斷,都是針對web請求的判斷。這組工具的使用方式是函數的鏈式調用,允許程式設計師將多個測試用例連結在一起,並進行多個判斷。
對於MockMvc如何初始化呢?可以使用MockMvcBuilders的build()方法進行構建,所以我們需要使用@Before在單元測試執行之前進行MockMvc對象的初始化:
private MockMvc mockMvc;
@Beforepublic void setupMockMvc(){ mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();}3.2 來測試一下web api吧
我們看下整體的代碼吧:
package com.kfit.springbootmockitodemo;
import org.hamcrest.Matchers;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.web.servlet.MockMvc;import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;import org.springframework.test.web.servlet.result.MockMvcResultMatchers;import org.springframework.test.web.servlet.setup.MockMvcBuilders;import org.springframework.web.context.WebApplicationContext;
@SpringBootTest@RunWith(SpringRunner.class)public class TestMockMvc {
@Autowired private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before public void setupMockMvc(){ mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); }
@Test public void testMvc() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/user/findById?id=1")) .andExpect(MockMvcResultMatchers.status().isOk()) ;
}
}這裡核心的就是關注testMvc,這裡andExpect()就是就是判斷請求返回的是200,如果不是的話,就會報錯哦:
3.3 報錯WebApplicationContext isrequired
如果是報錯:java.lang.IllegalArgumentException:WebApplicationContext is required:
這個錯誤的可能原因就是:
(1)沒有在單元測試類是添加註解@RunWith(SpringRunner.class);
(2)沒有在屬性上WebApplicationContext添加@Autowired;
3.4 中文亂碼
我們看下現在請求:/user/findById?id=1,返回的信息是:
如果我們要判斷這個json數據中的name的value是不是「師傅」這個字符串怎麼做呢 ?
@Testpublic void testMvc1() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/user/findById?id=1")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("師傅"))) .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("師傅")) ;}在上面的例子中提供了兩種方式進行比對,一種是字符串的包含的方式,另外一種就是使用的jsonPath獲取key的方式。
一運行就炸了:
亂的一批,真的是不忍直視,不讓看也不用打「馬賽克」呀。
怎麼去除「馬賽克」吶,很簡單,只需要添加一個content-type:
@Testpublic void testMvc2() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/user/findById?id=1") .accept(MediaType.APPLICATION_JSON_UTF8))
.andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("師傅"))) .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("師傅")) ;
}本篇文章接到這裡,我們下周《Mockito中捕獲mock對象方法的調用參數》詳解。
新課預告《大話設計模式之愛你一萬年》連載中:
我就是我,是顏色不一樣的煙火。
我就是我,是與眾不同的小蘋果。à悟空學院:https://t.cn/Rg3fKJD
學院中有Spring Boot相關的課程!點擊「閱讀原文」進行查看!
SpringBoot視頻:http://t.cn/A6ZagYTi
Spring Cloud視頻:http://t.cn/A6ZagxSR
SpringBoot Shiro視頻:http://t.cn/A6Zag7IV
SpringBoot交流平臺:https://t.cn/R3QDhU0
SpringData和JPA視頻:http://t.cn/A6Zad1OH
SpringSecurity5.0視頻:http://t.cn/A6ZadMBe
ShardingJDBC分庫分表:http://t.cn/A6ZarrqS
分布式事務解決方案:http://t.cn/A6ZaBnIr
JVM內存模型調優實戰:http://t.cn/A6wWMVqG
Spring入門到精通:https://t.cn/A6bFcDh4