偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

新來的騰訊后端,直接定義代碼測試新姿勢!

開發(fā) 后端
本文結(jié)合 SpringBootTest 和 Mockito兩個主流的測試框架,對 Controller各個職責(zé)進(jìn)行全面的測試,并且給出了比較詳細(xì)的示例代碼。

在日常工作中,看過很多開發(fā)人員不寫代碼測試,大部分理由是“太忙“或者”沒必要”,更嚴(yán)重的是很多開發(fā)人員甚至不知道如何寫測試代碼,本文我們總結(jié)了一位騰訊后端對 Controller層代碼優(yōu)秀的測試經(jīng)驗(yàn),希望對你有幫助。

在 如何編寫優(yōu)雅的 Controller代碼? 這篇文章中,我們分析了 Controller層的 6個主要職責(zé),本文將分析如何對 Controller層進(jìn)行360度無死角測試,首先回顧下 Controller層的6個主要職責(zé):

  • 接收 HTTP(s)請求
  • 解析請求參數(shù)
  • 校驗(yàn)請求參數(shù)
  • 調(diào)用業(yè)務(wù)方法
  • 組織返回?cái)?shù)據(jù)
  • 統(tǒng)一異常處理

理解了 Controller的職責(zé),才能更有目的對它進(jìn)行測試,如下代碼,包含了 6個主要職責(zé),我們該如何編寫測試代碼?

@RestController
public class UserController {
    private final UserService userService;
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/user/register")
    public String getGradeById(@Validated @RequestBody User user) {
        // 調(diào)用注冊的業(yè)務(wù)方法
        String userId = userService.register(user);
        return userId;
    }
}

public class User {
    @NotBlank(message = "Nickname is required.")
    private String nickname;
    private Integer age;
    // getters and setters and constructors
}

為什么要測試?

作為一名程序員,代碼質(zhì)量是我們必須守住的底線,對于自己編寫的代碼一定需要經(jīng)過測試,而不是把測試工作不負(fù)責(zé)的全部交給測試人員。

對于開發(fā)人員,保證代碼質(zhì)量最有效的方式是測試,最常見的測試方式有 2種:單元測試(Unit Testing)和 集成測試(Integration Testing)。

單元測試的目的是驗(yàn)證單個功能單元的行為是否正確,這里的功能單元通常是一個類或方法,單元測試最大的優(yōu)點(diǎn)是可以在不依賴于其他部分的前提下測試某個功能單元。

集成測試的目的是驗(yàn)證多個功能單元之間的交互是否正確,可能涉及數(shù)據(jù)庫、文件系統(tǒng)、網(wǎng)絡(luò)等外部系統(tǒng),如果需要排除外部系統(tǒng)的干擾,可以對他們進(jìn)行 mock。

如何測試?

對于 Controller層的代碼測試,因?yàn)閱卧獪y試的局限性,所以我們需要采用集成測試,本文將使用SpringBootTest 和 Mockito兩個主流的測試框架進(jìn)行分析,下面先說明幾個重要的組件:

1.@WebMvcTest

@WebMvcTest是 Spring Boot提供的一個注解,用于測試 SpringMVC的 Controller,它能夠啟動一個最小化的 Spring應(yīng)用上下文,包含僅與 Web層相關(guān)的 bean,從而快速且高效地測試 Controller的功能。

@WebMvcTest主要功能如下:

  • 加載 Web層相關(guān)的 Bean: @WebMvcTest只加載與 Web層相關(guān)的 bean,例如 Controller、過濾器、攔截器等,這使得測試環(huán)境更加輕量級。
  • 自動配置 MockMvc: @WebMvcTest 自動配置 MockMvc,使得測試控制器的 HTTP請求處理變得簡單。
  • 支持 @MockBean注解: 可以使用 @MockBean注解來模擬服務(wù)層的 bean,以隔離控制器測試,不依賴實(shí)際的服務(wù)層實(shí)現(xiàn)。

2.MockMvc

MockMvc是 Spring框架中用于測試 Spring MVC控制器的主要工具,它允許開發(fā)者在不啟動整個 HTTP服務(wù)器的情況下,測試控制器的請求處理方法。MockMvc 提供了一種方式來模擬 HTTP請求并驗(yàn)證響應(yīng),確??刂破餍袨榉项A(yù)期。

MockMvc的主要功能如下:

  • 模擬 HTTP 請求: MockMvc 可以模擬各種 HTTP 請求,如 GET、POST、PUT、DELETE 等。
  • 驗(yàn)證響應(yīng): MockMvc 提供了一組豐富的斷言來驗(yàn)證響應(yīng)的狀態(tài)碼、內(nèi)容類型、內(nèi)容、頭信息等。
  • 測試控制器邏輯: 通過模擬請求并驗(yàn)證響應(yīng),可以測試控制器的業(yè)務(wù)邏輯、路徑變量、請求參數(shù)、請求體等。
  • 集成測試: 可以與 Spring 的其他測試工具結(jié)合,進(jìn)行更復(fù)雜的集成測試。

3.Mockito

Mockito 是一個流行的 Java測試框架,用于創(chuàng)建和配置 mock 對象。它主要用于單元測試中,通過模擬依賴對象的行為,使得測試目標(biāo)對象能夠獨(dú)立于其依賴項(xiàng)進(jìn)行測試。

Mockito主要功能如下:

  • 創(chuàng)建 Mock 對象: 使用 @Mock注解或 Mockito.mock()方法創(chuàng)建 mock對象。
  • 定義行為: 使用 when 和 thenReturn 等方法定義 mock 對象的方法行為。
  • 驗(yàn)證行為: 使用 verify 方法驗(yàn)證 mock 對象的方法是否被調(diào)用,以及調(diào)用的次數(shù)和參數(shù)。
  • 參數(shù)匹配: 使用 any、eq 等參數(shù)匹配器來驗(yàn)證方法調(diào)用時傳入的參數(shù)。
  • 模擬異常: 使用 thenThrow 方法模擬方法拋出異常的行為。

4.ObjectMapper

它是 Jackson庫中的核心類之一,用于將 Java 對象轉(zhuǎn)換為 JSON 字符串,或者將 JSON 字符串轉(zhuǎn)換為 Java 對象。在 Spring 應(yīng)用中,ObjectMapper 被廣泛用于處理 JSON 數(shù)據(jù)。

ObjectMapper的主要功能如下:

  • 序列化(Serialization): 將 Java 對象轉(zhuǎn)換為 JSON 字符串。
  • 反序列化(Deserialization): 將 JSON 字符串轉(zhuǎn)換為 Java 對象。
  • 讀取和寫入 JSON 文件或流: 直接從文件、輸入流讀取 JSON 數(shù)據(jù),或?qū)?JSON 數(shù)據(jù)寫入文件、輸出流。

所以,一個包含上述所有組件的完整代碼示例如下:

@WebMvcTest(controllers = RegisterRestController.class)
class RegisterRestControllerTest {
  @Autowired
  private MockMvc mockMvc;
  @Autowired
  private ObjectMapper objectMapper;
  @MockBean
  private XXX xxx; // 用戶業(yè)務(wù)的bean

  @Test
  void test() throws Exception {
    mockMvc.perform(...);
  }
}

介紹了上面幾個集成測試的組件之后,接下來我們就可以詳解的分析他們是如何應(yīng)用到 Controller的集成測試中。

測試詳解

我們按照 Controller的 6個主要職責(zé)來分別講解他們是如何進(jìn)行測試的。

1.測試接收 HTTP(s)請求

Controller是接收請求的入口,因此對于 Controller接收 HTTP(s)請求驗(yàn)證 Controller是否偵聽某個 HTTP 請求非常簡單,我們只需調(diào)用 MockMvc.perform() 方法,返回 200代表成功,返回非200就代表異常,示例代碼如下:

@Test
void whenReceiveHttpRqe_thenReturns200() throws Exception {
    mockMvc.perform(post("/user/register")
        .contentType("application/json"))
        .andExpect(status().isOk()); 
}

2.測試解析請求參數(shù)

Controller是通過@PathVariable、@RequestBody、@RequestParam 3種方式來接收參數(shù)的,因此,下面的示例代碼分別模擬這 3種方式是如何進(jìn)行參數(shù)傳遞的。

@Autowired
private ObjectMapper objectMapper;
@Test
void whenValidInput_thenReturns200() throws Exception {
  User user = new User("zhangsan", 21);
  
   mockMvc.perform(post("/user/register/{id}", 1111) // 模擬通過 @PathVariable傳遞參數(shù)
        .contentType("application/json")
        .param("name", "張三") // 模擬通過 @RequestParam傳遞參數(shù)
        .content(objectMapper.writeValueAsString(user))) // 模擬通過 @RequestBody傳遞參數(shù)
        .andExpect(status().isOk());
}

通過上面的方式,我們模擬了一個正常的 HTTP請求,并且使用 3種方式進(jìn)行參數(shù)傳遞。

3.測試校驗(yàn)請求參數(shù)

測試參數(shù)的校驗(yàn),主要是為了檢查代碼邏輯有沒有對參數(shù)進(jìn)行有效的驗(yàn)證,比如,必填字段判空,字符串最大長度限制,數(shù)字最大值和最小值校驗(yàn),手機(jī)號或郵箱格式校驗(yàn)等。

參數(shù)校驗(yàn)測試一般分正常測試和按預(yù)期失敗的異常測試,特別需要進(jìn)行邊界的測試。如下示例,給出了測試通過和符合預(yù)期并返回 400的 BadRequest:

public class User {
    @NotBlank(message = "Nickname is required.")
    private String nickname;
    private Integer age;
    // getters and setters and constructors
}

@Test
void whenNicknameNull_thenReturns400() throws Exception {
  User user = new User(null, 21); // 當(dāng) nickname為空時,會拋出 400的 BadRequest異常
  mockMvc.perform(post("/user/register")
      .content(objectMapper.writeValueAsString(user)))
      .andExpect(status().isOk());
}
@Test
void testReturns200() throws Exception {
    User user = new User("zhangsan", 21);
    mockMvc.perform(post("/user/register")
        .content(objectMapper.writeValueAsString(user)))
        .andExpect(status().isBadRequest());
}

4.測試調(diào)用業(yè)務(wù)方法

對于業(yè)務(wù)方法調(diào)用的測試,通常我們會使用Mockito.mock來模擬業(yè)務(wù)方法的返回值,而業(yè)務(wù)方式的真實(shí)運(yùn)行邏輯會在 Server的單元測試中完成,如下示例代碼:

// 調(diào)用注冊的業(yè)務(wù)方法
String userId = userService.register(user);

@Test
void whenLogic_thenReturnsExceptData() throws Exception {
    User user = new User(null, 21);
    // mock userService.register(user)返回值為 userId
    Mockito.when(userService.register(user)).thenReturn("userId");

    mockMvc.perform(post("/user/register")
                    .content(objectMapper.writeValueAsString(user)))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.data", is("userId")));
}

5.測試組織返回?cái)?shù)據(jù)

在業(yè)務(wù)代碼執(zhí)行完之后,我們需要對 HTTP對應(yīng)響應(yīng),因此可以使用 andReturn()方法將 HTTP交互的結(jié)果存儲在 MvcResult類型的變量中,然后從響應(yīng)正文中讀取 JSON字符串,并使用 isEqualToIgnoringWhitespace()將其與預(yù)期字符串進(jìn)行比較,如下示例:

// 調(diào)用注冊的業(yè)務(wù)方法
String userId = userService.register(user);

@Test
void whenLogic_thenReturnsExceptData() throws Exception {
    User user = new User("zhangsan", 21);
    // mock userService.register(user)返回值為 userId
    Mockito.when(userService.register(user)).thenReturn("userId");

    MvcResult mvcResult = mockMvc.perform(post("/user/register")
        .content(objectMapper.writeValueAsString(user)))
        .andReturn(); //將結(jié)果返回
    String expectedResponse = "userId";
    String actualResponseBody = mvcResult.getResponse().getContentAsString();
    assertThat(actualResponseBody).isEqualToIgnoringWhitespace(
            objectMapper.writeValueAsString(expectedResponse));
}

6.測試統(tǒng)一異常處理

測試異是指如果發(fā)生異常,Controller應(yīng)返回特定的 HTTP狀態(tài),比如 200,400,500等等, 默認(rèn)情況下,Spring 會處理其中的大多數(shù)情況。但是,如果我們有一個自定義異常處理,我們想要測試它。假設(shè)我們要返回一個結(jié)構(gòu)化的 JSON 錯誤響應(yīng),其中包含請求中每個無效字段的字段名稱和錯誤消息。我們會創(chuàng)建一個這樣的@ControllerAdvice:

@Test
void whenNullValue_thenReturns400AndErrorResult() throws Exception {
  User user = new User("zhangsan", 21);

  MvcResult mvcResult = mockMvc.perform(post("/user/register")
          .contentType("application/json")
          .content(objectMapper.writeValueAsString(user)))
          .andExpect(status().isBadRequest())
          .andReturn();

  ErrorResult expectedErrorResponse = new ErrorResult("Nickname", "Nickname is required.");
  String actualResponse = mvcResult.getResponse().getContentAsString();
  String expectedResponseBody = objectMapper.writeValueAsString(expectedErrorResponse);
  assertThat(actualResponse).isEqualToIgnoringWhitespace(expectedErrorResponse);
}

總結(jié)

本文結(jié)合 SpringBootTest 和 Mockito兩個主流的測試框架,對 Controller各個職責(zé)進(jìn)行全面的測試,并且給出了比較詳細(xì)的示例代碼,通過本文的分析,我們不僅可以學(xué)會對 Controller的測試,同時還應(yīng)該觸類旁通,將里面優(yōu)秀的思維應(yīng)用到其他層級代碼的測試。

代碼質(zhì)量是開發(fā)人員必須守住的底線,所以在日常的開發(fā)中一定要秉著對自己負(fù)責(zé)的態(tài)度,采用單元測試和集成測試對自己的代碼進(jìn)行測試。

責(zé)任編輯:趙寧寧 來源: 猿java
相關(guān)推薦

2025-02-17 11:41:14

2024-10-28 07:10:00

scroll標(biāo)記前端網(wǎng)格布局

2021-05-26 08:21:43

@Autowired項(xiàng)目@Resouce

2024-03-07 12:11:31

PoetryPython代碼

2025-02-24 08:20:00

AI代碼生成

2024-04-30 11:49:16

瀏覽器前端開發(fā)折疊屏應(yīng)用

2024-01-18 15:17:56

谷歌云計(jì)算三星

2025-04-28 04:22:00

Spring動態(tài)SQL

2025-02-19 12:00:00

SpringBootDeepSeekAI

2019-02-27 09:08:20

Java 8StringJoineIDEA

2018-02-25 11:24:02

APPiPhone手機(jī)

2025-02-07 10:52:00

2016-09-07 09:20:54

2017-01-06 09:25:47

2025-02-04 00:05:53

架構(gòu)模式前后端

2018-03-06 17:24:57

2016-09-29 22:36:40

2021-10-05 15:41:30

Windows 11Windows微軟

2023-07-18 09:00:00

ChatGPT文本轉(zhuǎn)語音

2025-04-21 03:30:00

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號