學透Spring Boot — 010. 單元測試和Spring Test

系列文章目錄

這是CSDN postnull 博客《學透Spring Boot》系列的一篇,更多文章請移步:Postnull - 學透Spring Boot系列文章


文章目錄

  • 系列文章目錄
  • 前言
  • 1. 基本概念
    • UT 單元測試
    • TDD 測試驅動開發
    • UT測試框架
    • Mock框架
  • 3. Spring Test
    • 為什么要用Spring Test
    • 引入Spring Test
    • Spring Test最簡單使用


前言

開發的過程中,寫業務代碼是工作的一部分,測試也是工作的一部分。尤其是作為開發人員,用單元測試來測試我們的代碼,可以更早的發現bug。

1. 基本概念

UT 單元測試

單元測試 Unit Testing,通常是開發的一部分,也是開發過程中最小的測試單元。主要測試一個類或一個方法的邏輯。

因為只是保證我們自己寫的代碼的邏輯,所以是不涉及外部服務的(比如數據庫和外部接口),外部服務我們通常使用mock來模擬它們的行為。

UT是代碼片段的測試
外部集成測試才需要依賴真正的外部服務

TDD 測試驅動開發

近些年流行很多種 XDD,其中和測試相關的就是TDD,Test driven development,這是一種開發方法。

以前傳統的開發模式,我們先一口氣寫完業務代碼,然后再開始寫單元測試。但是會遇到一些問題:

  • 業務代碼不方便測試
  • 測試時才發現bug,導致業務代碼要做很大的調整

所以我們可以換一種思路,先寫測試用例,再寫業務代碼。
這也就是TDD的三個步驟,遵循 紅-綠-重構(Red-Green-Refactor)

  1. 紅:編寫一個失敗的測試。
  2. 綠:編寫代碼使測試通過。
  3. 重構:優化代碼,確保測試仍然通過。

我們先快速試一下
先寫個測試用例

public class CalculatorTest {@Testpublic void testAdd1() {Calculator calculator = new Calculator();assertEquals(3, calculator.add(1, 2));}@Testpublic void testAdd2() {Calculator calculator = new Calculator();assertEquals(0, calculator.add(1, -1));}
}

這個時候,測試用例是通不過的,因為我們的業務代碼類都還沒實現,編譯錯誤。當然這樣體驗不太好,我們也可以先實現業務代碼的骨架,只是空實現。

public class Calculator {public Integer add(int a, int b) {return null;}
}

我們運行一下測試用例,UT不通過,這也是預期的。
在這里插入圖片描述

然后我們開始實現代碼

public class Calculator {public Integer add(int a, int b) {return 0;}
}

這時候單元用例部分通過了
在這里插入圖片描述
說明我們的代碼有問題,繼續調整

public class Calculator {public Integer add(int a, int b) {return a + b;}
}

這次我們的UT都過了,表示代碼基本沒問題了。(基本沒問題不表示絕對沒問題,因為可能測試覆蓋率不夠,有些邊緣的case沒有考慮到。)

下次,我們的業務代碼被修改了,理論上出了bug,我們的測試用例是要失敗的。

public class Calculator {public Integer add(int a, int b) {if(a < 0 || b < 0){return null;}return a + b;}
}

在這里插入圖片描述
這時候,我們就需要注意了,是代碼有問題,還是測試用例需要更新。

轉換思路——測試先行

UT測試框架

Java最常用的 UT 框架有兩個

  1. Junit
  2. TestNG

其中Junit比較輕量,滿足大部分場景。TestNG功能更強大,比如支持并行測試(同時運行多個測試用例,Junit只能一個完了后再跑下一個)。具體對比:

  • TestNG 的@DataProvider,注入測試數據更方便,Junit5后提供的@ParameteriedTest也差不多功能
  • TestNG支持測試依賴,運行A用例前會自動先觸發B用例
  • TestNG支持測試分組,方便運行一組測試用例
  • TestNG支持用例并行執行,對相對獨立的case可以大大加快UT的時間
  • ……

TestNG更強大,但有時簡單就好

Mock框架

前面也說過,對于外部依賴,甚至是業務代碼其它的類,我們都應該模擬,這樣保證我們可以關注被測試的這個類和這個方法。
保證測試用例的能夠獨立、快速的被測試

有很多Mock框架

  • Mockito:最常用
  • PowerMock:兼容Mockito,功能更強大,比如測試靜態方法和私有方法(反思:private方法真的應該被測試嗎)

比如使用Mockito,步驟基本都是差不多的,先創建mock對象和行為,然后調用方法,最后驗證結果

public class UserServiceTest {@Testpublic void testGetUser() {// 1. 創建 Mock 對象UserRepository mockRepo = mock(UserRepository.class);// 2. 設置 Mock 行為when(mockRepo.findById(1)).thenReturn(new User(1, "John"));// 3. 調用測試方法UserService userService = new UserService(mockRepo);User user = userService.getUser(1);// 4. 驗證結果assertEquals("John", user.getName());}
}

3. Spring Test

為什么要用Spring Test

對于Java項目,直接使用TestNG/Junit + Mockito 不就可以了嗎?為什么還要用 Spring Test?

以前也有這個疑問,但是如果我們測試Spring 項目時,Junit + Mockito 就有點力不從心了。比如:

  • 注入Spring的配置,比如application-test.xml中配置,注入到Spring容器中去
  • 自動注入Bean,這個做不到,得手動new對象
  • 模擬HTTP請求,這個也做不到,所以Controller測試不了
  • 測試Spring整個應用,也做不到,只能測試單個類

Spring Test就是為了更方便的測試Spring 應用

當然,Spring Test不是要取代 TestNG/Junit + Mockito, 想法,它底層用的還是這些技術。
它只是提供了一堆工具和注解,幫助我們更方便測試Spring應用。

引入Spring Test

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>

我們在關聯依賴中也可以看到,它自動引入了Junit和Mockito
在這里插入圖片描述
這框架本身包含了兩個模塊

  1. Spring Test 核心模塊 spring-boot-test
  2. 自動配置模塊 spring-boot-test-autoconfigure: 我們很多自動配置,比如注入
    在這里插入圖片描述
    比如在自動配置的模塊中,我們可以看到MockMvc的自動配置。這個類我們以后測試會經常遇到。在這里插入圖片描述

Spring Test最簡單使用

本文我們先來個最簡單的例子,測試我們的Controller。

@RestController
@RequestMapping("/tn-users")
public class TnUserController {private TnUserService tnUserService;public TnUserController(TnUserService tnUserService) {this.tnUserService = tnUserService;}@GetMapping("/{id}")public ResponseEntity<TypiUser> getUser(@PathVariable int id) {TypiUser user = tnUserService.getUserById(id);return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();}
}

然后我們編寫測試用例

@WebMvcTest(TnUserController.class)
public class TnUserControllerTest {@Autowiredprivate MockMvc mockMvc;@MockitoBeanprivate TnUserService tnUserService;@Test@DisplayName("測試成功查詢用戶的情況")public void testGetUser() throws Exception {//givenTypiUser mockUser = TypiUser.builder().id(1234).name("Joe").build();//whenwhen(tnUserService.getUserById(eq(1234))).thenReturn(mockUser);//thenmockMvc.perform(get("/tn-users/{id}", 1234)).andExpect(status().isOk()).andExpect(jsonPath("$.id").value(1234)).andExpect(jsonPath("$.name").value("Joe"));}
}

測試通過
在這里插入圖片描述
稍微改一下代碼,再次運行,會發現報錯。

        mockMvc.perform(get("/tn-users/{id}", 1234)).andExpect(status().isBadRequest());

在這里插入圖片描述
可以看到,我們現在具備測試Controller層的能力了。如果沒有Spring Test,只是靠Mockito基本做不到接口層的測試。

我們先不用關注實現的細節。下一篇文章我們會全面介紹Spring Test的使用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/76114.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/76114.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/76114.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Chrome 135 版本新特性

Chrome 135 版本新特性 一、Chrome 135 版本瀏覽器更新 ** 1. 第三方托管賬戶注冊遷移到 OIDC 授權碼流程** Chrome 135 將賬戶注冊的登錄頁面從營銷網站遷移到動態網站&#xff0c;同時也將 OpenID Connect (OIDC) 的隱式流程遷移到授權碼流程。這樣做的目的是進一步提升第…

Docker Swarm集群搭建與管理全攻略

文章目錄 一、節點準備二、初始化 manager 節點三、管理 swarm 集群中的 worker 節點1、添加 worker 節點2、查看 worker 節點3、刪除 worker 節點 四、管理 swarm 集群服務1、創建服務2、查看服務3、刪除服務 五、管理 swarm 節點服務1、節點標簽管理2、創建服務3、查看服務4、…

離線語音識別 ( 小語種國家都支持)可定制詞組

1產品介紹 離線語音模組采用神經網絡算法&#xff0c;支持語音識別、自學習等功能。運用此模組將 AI 技 術賦能產品&#xff0c;升級改造出語音操控的智能硬件 ( 例如風扇、臺燈、空調、馬桶、按摩椅、運 動相機、行車記錄儀等 ) 。支持全球多種語言識別&#xff0c;如中文…

Docker與VNC的使用

https://hub.docker.com/r/dorowu/ubuntu-desktop-lxde-vnc 下載nvc 客戶端 https://downloads.realvnc.com/download/file/viewer.files/VNC-Viewer-7.12.0-Windows.exe 服務端 docker pull dorowu/ubuntu-desktop-lxde-vnc#下載成功 docker pull dorowu/ubuntu-desktop-l…

Linux系統學習Day0——了解和熟悉Linux系統的遠程終端登錄和數據傳輸

一、Windows系統與Linux系統虛擬機通過橋接進行網絡連接 &#xff08;一&#xff09;橋接模式 橋接模式是虛擬機網絡連接的一種常見方式&#xff0c;其核心原理是通過虛擬網卡將Linux虛擬機與宿主機的物理網卡建立橋接關系&#xff0c;使虛擬機能夠直接接入物理網絡。在該模式…

【開題報告+論文+源碼】基于springboot的農貿菜市場租位管理系統的設計與實現

項目背景與意義 隨著信息技術的快速發展和普及&#xff0c;信息化管理已成為各行業提升運營效率和服務質量的重要手段。農貿菜市場作為城市生活的重要組成部分&#xff0c;其管理效率和服務水平直接關系到市民的日常生活體驗。傳統的農貿菜市場租位管理方式往往存在信息不對稱、…

Codecademy—— 交互式編程學習的樂園

一、網站概述 Codecademy 是一家美國在線學習編程知識的網站&#xff0c;它為編程學習者提供了一種全新的學習方式。在如今眾多的編程學習平臺中&#xff0c;Codecademy 憑借其獨特的優勢脫穎而出&#xff0c;吸引了全球數百萬用戶。其目標是幫助更多人輕松學習編程&#xff0…

WEB安全--XSS--DOM破壞

一、前言 繼XSS基礎篇后&#xff0c;我們知道了三種類型的XSS&#xff0c;這篇文章主要針對DOM型XSS的原理進行深入解析。 二、DOM型XSS原理 2.1、什么是DOM 以一個形象的比喻&#xff1a; 網頁就像是一座房子&#xff0c;而 **DOM** 就是這座房子的“藍圖”或者“結構圖”。…

Linux系統遠程操作和程序編譯

Linux系統遠程操作和程序編譯 了解和熟悉Linux系統的遠程終端登錄、遠程圖形桌面訪問、 X圖形窗口訪問和FTP文件傳輸操作 網絡設置和用戶創建&#xff1a; 在虛擬機Ubuntu系統中&#xff0c;將網絡連接設置為“橋接模式”&#xff0c;并配置好IP和網關。確保其他Windows 10系統…

linux開發環境

1.虛擬機環境搭建 在 Ubuntu 系統中&#xff0c;打開&#xff08;如圖中顯示的窗口 &#xff09;常見快捷鍵有&#xff1a; Ctrl Alt T&#xff1a;這是最常用的打開終端的快捷鍵組合 &#xff0c;按下后會快速彈出一個新的終端窗口。 在 VMware 虛擬機環境中&#xff0c;若…

藍橋·20264-祝福語--找連續字串的長度

#include <iostream> using namespace std; int main() {// 請在此輸入您的代碼//最小字典序&#xff0c;一定是全a&#xff0c;找s的最長字串a,結果就是該字串長度加1&#xff08;t不能是s的子串&#xff09;//所以這道題就變成了&#xff0c;找s中字串a出現的長度strin…

7.第二階段x64游戲實戰-分析人物屬性

免責聲明&#xff1a;內容僅供學習參考&#xff0c;請合法利用知識&#xff0c;禁止進行違法犯罪活動&#xff01; 本次游戲沒法給 內容參考于&#xff1a;微塵網絡安全 上一個內容&#xff1a;6.第二階段x64游戲實戰-分析人物狀態 首先打開人物面板&#xff0c;查看人物的…

數組的常見算法一

注: 本文來自尚硅谷-宋紅康僅用來學習備份 6.1 數值型數組特征值統計 這里的特征值涉及到&#xff1a;平均值、最大值、最小值、總和等 **舉例1&#xff1a;**數組統計&#xff1a;求總和、均值 public class TestArrayElementSum {public static void main(String[] args)…

汽車電子筆記之:基于Tasking編譯器怎么制作庫文件并將庫文件集成進工程釋放

目錄 1、概述 2、庫工程創建、使用步驟 2.1、選擇對應的MCU型號及空工程 2.2、選擇需要封裝的代碼 2.3、將需要封裝的代碼復制到庫工程 2.4、整理庫工程工程屬性 2.5、預留不生成庫的.c源文件 2.6、編譯生成.a文件 2.7、將.a集成進工程 2.7.1、創建釋放給客戶的工程 …

[ctfshow web入門] web29

前置知識 eval: 把字符串按照 PHP 代碼來執行&#xff0c;例如eval(“echo 1;”);這個函數擁有回顯 system&#xff1a;使php程序執行系統命令&#xff0c;例如&#xff0c;system(“ls”);就是查看當前目錄&#xff0c;這個擁有回顯 preg_match&#xff1a;查找字符串是否匹配…

7-8 超速判斷

模擬交通警察的雷達測速儀。輸入汽車速度&#xff0c;如果速度超出60 mph&#xff0c;則顯示“Speeding”&#xff0c;否則顯示“OK”。 輸入格式&#xff1a; 輸入在一行中給出1個不超過500的非負整數&#xff0c;即雷達測到的車速。 輸出格式&#xff1a; 在一行中輸出測…

【GESP】C++二級練習 luogu-B3721 [語言月賽202303] Stone Gambling S

GESP二級練習&#xff0c;多層循環分支練習&#xff0c;難度★?☆☆☆。 題目題解詳見&#xff1a;https://www.coderli.com/gesp-2-luogu-b3721/ 【GESP】C二級練習 luogu-B3721 [語言月賽202303] Stone Gambling S | OneCoderGESP二級練習&#xff0c;多層循環分支練習&am…

深入理解C++面向對象特性之一 多態

歡迎來到干貨小倉庫&#xff0c;堪比沙漠!!! 從“Hello World”到改變世界&#xff0c;中間隔著千萬次再試一次. 1.多態的概念 多態的概念&#xff1a;通俗來說&#xff0c;就是多種形態&#xff0c; 具體點就是去完成某個行為&#xff0c;當不同的對象去完成時會 產生出不同的…

藍橋備賽指南(14):樹的直徑與重心

樹的直徑 什么是樹的直徑&#xff1f;樹的直徑是樹上最長的一條鏈&#xff0c;當然這條鏈并不唯一&#xff0c;所以一棵樹可能有多條直徑。直徑由兩個頂點u、v來決定&#xff0c;若由一條直徑&#xff08;u,v)&#xff0c;則滿足一下性質&#xff1a; 1&#xff09;u、v的度數…

AIDD-人工智能藥物設計-網絡藥理學-多組學與網絡藥理學分析揭示龜齡集治療少精癥的機制

IF6.7|多組學與網絡藥理學分析揭示龜齡集治療少精癥的機制 2024年10月28日&#xff0c;海軍軍醫大學張衛東教授團隊在Phytomedicine&#xff08;IF6.7&#xff09;上發表了題為“Multi-omics and network pharmacology approaches reveal Gui-Ling-Ji alleviates oligoastheno…