最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Mock測試Spring MVC接口過程解析

 更新時間:2020年11月18日 14:34:13   作者:碼農(nóng)小胖哥  
這篇文章主要介紹了基于Mock測試Spring MVC接口過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

1. 前言

在Java開發(fā)中接觸的開發(fā)者大多數(shù)不太注重對接口的測試,結(jié)果在聯(lián)調(diào)對接中出現(xiàn)各種問題。也有的使用Postman等工具進行測試,雖然在使用上沒有什么問題,如果接口增加了權(quán)限測試起來就比較惡心了。所以建議在單元測試中測試接口,保證在交付前先自測接口的健壯性。今天就來分享一下胖哥在開發(fā)中是如何對Spring MVC接口進行測試的。

在開始前請務(wù)必確認添加了Spring Boot Test相關(guān)的組件,在最新的版本中應(yīng)該包含以下依賴:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
  <exclusions>
    <exclusion>
      <groupId>org.junit.vintage</groupId>
      <artifactId>junit-vintage-engine</artifactId>
    </exclusion>
  </exclusions>
</dependency>

本文是在Spring Boot 2.3.4.RELEASE下進行的。

2. 單獨測試控制層

如果我們只需要對控制層接口(Controller)進行測試,且該接口不依賴@Service、@Component等注解聲明的Spring Bean時,可以借助@WebMvcTest來啟用只針對Web控制層的測試,例如

@WebMvcTest
class CustomSpringInjectApplicationTests {
  @Autowired
  MockMvc mockMvc;

  @SneakyThrows
  @Test
  void contextLoads() {
    mockMvc.perform(MockMvcRequestBuilders.get("/foo/map"))
        .andExpect(ResultMatcher.matchAll(status().isOk(),
            content().contentType(MediaType.APPLICATION_JSON),
            jsonPath("$.test", Is.is("hello"))))
        .andDo(MockMvcResultHandlers.print());
  }

}

這種方式要快的多,它只加載了應(yīng)用程序的一小部分。但是如果你涉及到服務(wù)層這種方式是不湊效的,我們就需要另一種方式了。

3. 整體測試

大多數(shù)Spring Boot下的接口測試是整體而又全面的測試,涉及到控制層、服務(wù)層、持久層等方方面面,所以需要加載比較完整的Spring Boot上下文。這時我們可以這樣做,聲明一個抽象的測試基類:

package cn.felord.custom;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;


/**
 * 測試基類,
 * @author felord.cn
 */
@SpringBootTest
@AutoConfigureMockMvc
abstract class CustomSpringInjectApplicationTests {
  /**
   * The Mock mvc.
   */
  @Autowired
  MockMvc mockMvc;
  // 其它公共依賴和處理方法 
}

只有當@AutoConfigureMockMvc存在時MockMvc才會被注入Spring IoC。

然后針對具體的控制層進行如下測試代碼的編寫:

package cn.felord.custom;

import lombok.SneakyThrows;
import org.hamcrest.core.Is;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

/**
 * 測試FooController.
 *
 * @author felord.cn
 */
public class FooTests extends CustomSpringInjectApplicationTests {
  /**
   * /foo/map接口測試.
   */
  @SneakyThrows
  @Test
  void contextLoads() {
    mockMvc.perform(MockMvcRequestBuilders.get("/foo/map"))
        .andExpect(ResultMatcher.matchAll(status().isOk(),
            content().contentType(MediaType.APPLICATION_JSON),
            jsonPath("$.test", Is.is("bar"))))
        .andDo(MockMvcResultHandlers.print());
  }
}

4. MockMvc測試

集成測試時,希望能夠通過輸入URL對Controller進行測試,如果通過啟動服務(wù)器,建立http client進行測試,這樣會使得測試變得很麻煩,比如,啟動速度慢,測試驗證不方便,依賴網(wǎng)絡(luò)環(huán)境等,為了可以對Controller進行測試就引入了MockMvc。

MockMvc實現(xiàn)了對Http請求的模擬,能夠直接使用網(wǎng)絡(luò)的形式,轉(zhuǎn)換到Controller的調(diào)用,這樣可以使得測試速度快、不依賴網(wǎng)絡(luò)環(huán)境,而且提供了一套驗證的工具,這樣可以使得請求的驗證統(tǒng)一而且很方便。接下來我們來一步步構(gòu)造一個測試的模擬請求,假設(shè)我們存在一個下面這樣的接口:

@RestController
@RequestMapping("/foo")
public class FooController {
  @Autowired
  private MyBean myBean;

  @GetMapping("/user")
  public Map<String, String> bar(@RequestHeader("Api-Version") String apiVersion, User user) {
    Map<String, String> map = new HashMap<>();
    map.put("test", myBean.bar());
    map.put("version", apiVersion);
    map.put("username", user.getName());
    //todo your business
    return map;
  }
}

參數(shù)設(shè)定為name=felord.cn&age=18,那么對應(yīng)的HTTP報文是這樣的:

GET /foo/user?name=felord.cn&age=18 HTTP/1.1
Host: localhost:8888
Api-Version: v1

可以預(yù)見的返回值為:

{
  "test": "bar",
  "version": "v1",
  "username": "felord.cn"
}

事實上對接口的測試可以分為以下幾步。

構(gòu)建請求

構(gòu)建請求由MockMvcRequestBuilders負責(zé),他提供了請求方法(Method),請求頭(Header),請求體(Body),參數(shù)(Parameters),會話(Session)等所有請求的屬性構(gòu)建。/foo/user接口的請求可以轉(zhuǎn)換為:

MockMvcRequestBuilders.get("/foo/user")
.param("name", "felord.cn")
.param("age", "18")
.header("Api-Version", "v1")

執(zhí)行Mock請求

然后由MockMvc執(zhí)行Mock請求:

mockMvc.perform(MockMvcRequestBuilders.get("/foo/user")
.param("name", "felord.cn")
.param("age", "18")
.header("Api-Version", "v1"))

對結(jié)果進行處理

請求結(jié)果被封裝到ResultActions對象中,它封裝了多種讓我們對Mock請求結(jié)果進行處理的方法。

對結(jié)果進行預(yù)期期望

ResultActions#andExpect(ResultMatcher matcher)方法負責(zé)對響應(yīng)的結(jié)果的進行預(yù)期期望,看看是否符合測試的期望值。參數(shù)ResultMatcher負責(zé)從響應(yīng)對象中提取我們需要期望的部位進行預(yù)期比對。

假如我們期望接口/foo/user返回的是JSON,并且HTTP狀態(tài)為200,同時響應(yīng)體包含了version=v1的值,我們應(yīng)該這么聲明:

ResultMatcher.matchAll(MockMvcResultMatchers.status().isOk(),
MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON),
MockMvcResultMatchers.jsonPath("$.version", Is.is("v1")));

JsonPath是一個強大的JSON解析類庫,請通過其項目倉庫https://github.com/json-path/JsonPath了解。

對響應(yīng)進行處理

ResultActions#andDo(ResultHandler handler)方法負責(zé)對整個請求/響應(yīng)進行打印或者log輸出、流輸出,由MockMvcResultHandlers工具類提供這些方法。我們可以通過以上三種途徑來查看請求響應(yīng)的細節(jié)。

例如/foo/user接口:

MockHttpServletRequest:
   HTTP Method = GET
   Request URI = /foo/user
    Parameters = {name=[felord.cn], age=[18]}
     Headers = [Api-Version:"v1"]
       Body = null
  Session Attrs = {}

Handler:
       Type = cn.felord.xbean.config.FooController
      Method = cn.felord.xbean.config.FooController#urlEncode(String, Params)

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 = {"test":"bar","version":"v1","username":"felord.cn"}
  Forwarded URL = null
  Redirected URL = null
     Cookies = []

獲取返回結(jié)果

如果你希望進一步處理響應(yīng)的結(jié)果,也可以通過ResultActions#andReturn()拿到MvcResult類型的結(jié)果進行進一步的處理。

完整的測試過程

通常andExpect是我們必然會選擇的,而andDo和andReturn在某些場景下會有用,它們兩個是可選的。我們把上面的連在一起。

@Autowired
MockMvc mockMvc;

@SneakyThrows
@Test
void contextLoads() {
   mockMvc.perform(MockMvcRequestBuilders.get("/foo/user")
      .param("name", "felord.cn")
      .param("age", "18")
      .header("Api-Version", "v1"))
      .andExpect(ResultMatcher.matchAll(status().isOk(),
          content().contentType(MediaType.APPLICATION_JSON),
          jsonPath("$.version", Is.is("v1"))))
      .andDo(MockMvcResultHandlers.print());
      
}

這種流式的接口單元測試從語義上看也是比較好理解的,你可以使用各種斷言、正例、反例測試你的接口,最終讓你的接口更加健壯。

5. 總結(jié)

一旦你熟練了這種方式,你編寫的接口將更加具有權(quán)威性而不會再漏洞百出,甚至有時候你也可以使用Mock來設(shè)計接口,使之更加貼合業(yè)務(wù)。所以CRUD不是完全沒有技術(shù)含量,高質(zhì)量高效率的CRUD往往需要這種工程化的單元測試來支撐。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • springboot?vue測試列表遞歸查詢子節(jié)點下的接口功能實現(xiàn)

    springboot?vue測試列表遞歸查詢子節(jié)點下的接口功能實現(xiàn)

    這篇文章主要為大家介紹了springboot?vue測試列表遞歸查詢子節(jié)點下的接口功能實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • mybatis打印SQL,并顯示參數(shù)的實例

    mybatis打印SQL,并顯示參數(shù)的實例

    這篇文章主要介紹了mybatis打印SQL,并顯示參數(shù)的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Java調(diào)用Oss JDk實現(xiàn)刪除指定目錄下的所有文件

    Java調(diào)用Oss JDk實現(xiàn)刪除指定目錄下的所有文件

    這篇文章主要為大家詳細介紹了Java如何調(diào)用Oss JDk實現(xiàn)刪除指定目錄下的所有文件功能,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2025-03-03
  • Java中可以實現(xiàn)負載均衡的算法詳解

    Java中可以實現(xiàn)負載均衡的算法詳解

    這篇文章主要介紹了Java中可以實現(xiàn)負載均衡的算法詳解,在Java中,有多種算法可以實現(xiàn)負載均衡,下面是兩個常見的算法示例,隨機算法和輪詢算法,需要的朋友可以參考下
    2023-08-08
  • 詳談jvm--Java中init和clinit的區(qū)別

    詳談jvm--Java中init和clinit的區(qū)別

    下面小編就為大家?guī)硪黄斦刯vm--Java中init和clinit的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • SpringBoot@Componet注解注入失敗的問題

    SpringBoot@Componet注解注入失敗的問題

    這篇文章主要介紹了SpringBoot@Componet注解注入失敗的問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java多線程通信wait()和notify()代碼實例

    Java多線程通信wait()和notify()代碼實例

    這篇文章主要介紹了Java多線程通信wait()和notify()代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • 淺談Java中的atomic包實現(xiàn)原理及應(yīng)用

    淺談Java中的atomic包實現(xiàn)原理及應(yīng)用

    這篇文章主要介紹了淺談Java中的atomic包實現(xiàn)原理及應(yīng)用,涉及Atomic在硬件上的支持,Atomic包簡介及源碼分析等相關(guān)內(nèi)容,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • java實現(xiàn)文件上傳的詳細步驟

    java實現(xiàn)文件上傳的詳細步驟

    文件上傳是用戶將本地文件通過Web頁面提交到服務(wù)器的過程,涉及客戶端、服務(wù)器端、上傳表單等組件,在SpringBoot中,通過MultipartFile接口處理上傳文件,并將其保存在服務(wù)器,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-10-10
  • 自主配置數(shù)據(jù)源,mybatis/plus不打印sql日志問題

    自主配置數(shù)據(jù)源,mybatis/plus不打印sql日志問題

    這篇文章主要介紹了自主配置數(shù)據(jù)源,mybatis/plus不打印sql日志問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12

最新評論

西乌| 安图县| 祁东县| 成安县| 枞阳县| 林西县| 同仁县| 昭通市| 藁城市| 樟树市| 新和县| 井冈山市| 承德县| 遂宁市| 五寨县| 时尚| 灵璧县| 大关县| 板桥市| 田阳县| 阿鲁科尔沁旗| 大竹县| 贵阳市| 中方县| 宁化县| 巴彦淖尔市| 准格尔旗| 鹰潭市| 新沂市| 嘉兴市| 襄汾县| 镇雄县| 崇义县| 广宗县| 婺源县| 滦平县| 陆河县| 罗田县| 麻阳| 卢氏县| 化隆|