保姆級教程:Spring Boot 單元測試

作者 | 小名同學
一、 單元測試的概念
概念:
單元測試(unit testing),是指對軟件中的最小可測試單元進行檢查和驗證。在Java中單元測試的最小單元是類。
單元測試是開發(fā)者編寫的一小段代碼,用于檢驗被測代碼的一個很小的、很明確的功能是否正確。執(zhí)行單元測試,就是為了證明這 段代碼的行為和我們期望是否一致。
單元測試引用:
眾所周知,通過spring initialize創(chuàng)建的Spring Boot項目會在Maven中自動攜帶很多starter依賴:

其中包含了一個名為spring-boot-starter-test的依賴,本文是圍繞這個依賴展開。
Spring Boot中引入單元測試很簡單,添加如下依賴(即 spring-boot-starter-test依賴):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
spring-boot-starter-test有如下幾個庫:
spring-boot-starter-testUML圖:


@Autowire 和 @Resource 注解使用的正確姿勢,別再用錯的了!!
二、單元測試的作用
在沒有接觸單元測試之前我們是怎么做測試的?一般有兩個方法:

在時間允許的情況下,編寫單元測試是程序員對代碼的自測,這是對自己代碼的負責。
寫單元測試的兩個動機:
保證或驗證實現(xiàn)功能。
保護已經(jīng)實現(xiàn)的功能不被破壞。
三、Spring Boot引入的MockMvc的概念
什么是Mock?
在面向?qū)ο蟮某绦蛟O(shè)計中,模擬對象(英語:mock object)是以可控的方式模擬真實對象行為的假對象。在編程過程中,通常通過模擬一些輸入數(shù)據(jù),來驗證程序是否達到預(yù)期結(jié)果。
為什么使用Mock對象?
使用模擬對象,可以模擬復(fù)雜的、真實的對象行為。如果在單元測試中無法使用真實對象,可采用模擬對象進行替代。
MockMvc的概念
MockMvc是由spring-test包提供,實現(xiàn)了對Http請求的模擬,能夠直接使用網(wǎng)絡(luò)的形式,轉(zhuǎn)換到Controller的調(diào)用,使得測試速度快、不依賴網(wǎng)絡(luò)環(huán)境。同時提供了一套驗證的工具,結(jié)果的驗證十分方便。
接口MockMvcBuilder,提供一個唯一的build方法,用來構(gòu)造MockMvc。主要有兩個實現(xiàn):StandaloneMockMvcBuilder和DefaultMockMvcBuilder。

Java實現(xiàn)pdf和Excel的生成及數(shù)據(jù)動態(tài)插入、導出
MockMVC的基本步驟
(1) mockMvc.perform執(zhí)行一個請求。(2) MockMvcRequestBuilders.get(“XXX”)構(gòu)造一個請求。(3) ResultActions.param添加請求傳值 (4) ResultActions.accept()設(shè)置返回類型 (5) ResultActions.andExpect添加執(zhí)行完成后的斷言。(6) ResultActions.andDo添加一個結(jié)果處理器,表示要對結(jié)果做點什么事情,比如處使用print()輸出整個響應(yīng)結(jié)果信息。(7) ResultActions.andReturn表示執(zhí)行完成后返回相應(yīng)的結(jié)果。
四、Service層的單元測試
第一步: Spring Boot中單元測試類寫在src/test/java目錄下,你可以手動創(chuàng)建具體測試類,也可以通過IDEA自動創(chuàng)建測試類,如下圖:(注:點選并打開相應(yīng)代碼界面,再點擊菜單欄的Navigate)

好用到爆!多種數(shù)據(jù)庫只需一個工具就能搞定!
第二步: 按照第一步的方法,點擊測試后,出現(xiàn)圖一 的對話框(如果想要測試的類已經(jīng)存在測試類了會被列出來,也可以重新創(chuàng)建一個新的測試類),點擊”Create New Test…”會彈出圖二 的對話框,可以選擇是否生成setUp以及要測試的成員方法等:
圖一

圖二

超詳細解讀Java接口:模塊通信協(xié)議以及默認方法和靜態(tài)方法
第三步: 至此Service層的測試類就創(chuàng)建好了,測試類自動生成到了src/test/java目錄下項目的同級目錄中 ,如下圖:

Service層測試代碼如下:
@SpringBootTest
@RunWith(SpringRunner.class)
public class XXXServiceTest {
@Resource
private XXXService XXXService;
@Test
public void conflictTime() {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate start = LocalDate.parse("2020-10-26", dtf);
LocalDate end = LocalDate.parse("2020-10-31", dtf);
Integer integer = XXXService.ConflictTime("10000001", start, end);
Assert.assertThat(integer, Matchers.notNullValue());//assertThat斷言后面介紹
}
}
注解解釋:
@SpringBootTest:獲取啟動類,加載配置,尋找主配置啟動類(被 @SpringBootApplication 注解的) @RunWith(SpringRunner.class):讓JUnit運行Spring的測試環(huán)境,獲得Spring環(huán)境的上下文的支持
五、Controller層的單元測試
創(chuàng)建測試類步驟見第四部分,此處略。
第四部分只是針對Service層做了測試,但是咱么也需要對Controller層(API)做測試,這時候就用到MockMvc了,它使得你無需啟動項目工程就能測試這些接口
MockMvc實現(xiàn)了對Http請求的模擬,能夠直接使用網(wǎng)絡(luò)的形式,轉(zhuǎn)換到Controller的調(diào)用,這樣可以使得測試速度快、不依賴網(wǎng)絡(luò)環(huán)境,而且提供了一套驗證的工具,這樣可以使得請求的驗證統(tǒng)一而且很方便。
Controller層部分的代碼將分為三個代碼塊講解,里面有看不懂的代碼先不要著急哦??,會在第五部分結(jié)尾處給大家匯總解答的,大家要堅持看到最后喲!??
代碼塊一:
@SpringBootTest
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
public class DfTaskRecordControllerTest {
@Autowired
private MockMvc mockMvc;
@Before
public void setUp() throws Exception {
System.out.println("---------------start---------------");
save();
get();
System.out.println("================end================");
}
注解解釋:
@SpringBootTest>:獲取啟動類,加載配置,尋找主配置啟動類(被 @SpringBootApplication 注解的)
@RunWith(SpringRunner.class)>:讓JUnit運行Spring的測試環(huán)境,獲得Spring環(huán)境的上下文的支持 @AutoConfigureMockMvc:用于自動配置MockMvc,配置后MockMvc類可以直接注入,相當于new MockMvc @Before:初始化方法 ,對于每一個測試方法都要執(zhí)行一次
代碼塊二:
@Test
@Transactional
@Rollback()
public void save() throws Exception {
String json"{……}";
//執(zhí)行一個RequestBuilder請求,會自動執(zhí)行SpringMVC的流程并映射到相應(yīng)的控制器執(zhí)行處理;
mockMvc.perform(MockMvcRequestBuilders
.post("/XXX/save")
.content(json.getBytes()) //傳json參數(shù)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.header("Authorization","Bearer ********-****-****-****-************")
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(print());
}
注解解釋:
@Transactional:開啟事務(wù)功能
@Rollback(): 事務(wù)回滾,默認是true
代碼塊三:
@Test
public void get() throws Exception{
ResultActions resultActions = mockMvc.perform(MockMvcRequestBuilders
.get("/XXX/get")
.param("id", "**********")
.header("Authorization", "Bearer ********-****-****-****-************")
);
resultActions.andReturn().getResponse().setCharacterEncoding("UTF-8");
resultActions.andExpect(MockMvcResultMatchers.status().isOk()).andDo(print());
}
}
/get運行結(jié)果如下:

本科畢業(yè)出國率下降,考研or保研?條條大路通「內(nèi)卷」
現(xiàn)在將上面的一些瑣碎的知識點匯總一下:
1. mockMvc.perform:執(zhí)行一個請求
2. MockMvcRequestBuilders.get(“/XXX/get”):構(gòu)造一個請求,Post請求使用.post方法
3. contentType(MediaType.APPLICATION_JSON_VALUE):代表發(fā)送端發(fā)送的數(shù)據(jù)格式是application/json;charset=UTF-8
4. accept(MediaType.APPLICATION_JSON):代表客戶端希望接受的數(shù)據(jù)類型為application/json;charset=UTF-8
5. header(“Authorization”,“Bearer XXXX”):代表在報文頭添加一些必須的信息,這里添加的是token
6. ResultActions.andExpect:添加執(zhí)行完成后的斷言
7. ResultActions.andExpect(MockMvcResultMatchers.status().isOk()):方法看請求的狀態(tài)響應(yīng)碼是否為200如果不是則拋異常,測試不通過
8. ResultActions.andDo:添加一個結(jié)果處理器,表示要對結(jié)果做點什么事情,比如此處使用print():輸出整個響應(yīng)結(jié)果信息
六、斷言的概念
斷言(assert),是編程術(shù)語,表示為一些布爾表達式,程序員相信在程序中的某個特定點該表達式值為真。可以在任何時候啟用和禁用斷言驗證,因此可以在測試時啟用斷言而在部署時禁用斷言。 使用斷言是判斷一個函數(shù)或?qū)ο蟮囊粋€方法所產(chǎn)生的結(jié)果是否符合你期望那個結(jié)果。
七、新斷言assertThat使用
JUnit 4.4 結(jié)合 Hamcrest 提供了一個全新的斷言語法——assertThat。程序員可以只使用 assertThat 一個斷言語句,結(jié)合 Hamcrest 提供的匹配符,就可以表達全部的測試思想。
assertThat 的優(yōu)點:
優(yōu)點 1: 以前 JUnit 提供了很多的 assertion 語句,如:assertEquals,assertNotSame,assertFalse,assertTrue,assertNotNull,assertNull 等,現(xiàn)在有了 JUnit 4.4,一條 assertThat 即可以替代所有的 assertion 語句,這樣可以在所有的單元測試中只使用一個斷言方法,使得編寫測試用例變得簡單,代碼風格變得統(tǒng)一,測試代碼也更容易維護。
優(yōu)點 2: assertThat 使用了 Hamcrest 的 Matcher 匹配符,用戶可以使用匹配符規(guī)定的匹配準則精確的指定一些想設(shè)定滿足的條件,具有很強的易讀性,而且使用起來更加靈活。
優(yōu)點 3: assertThat 不再像 assertEquals 那樣,使用比較難懂的“謂賓主”語法模式(如:assertEquals(3, x);),相反,assertThat 使用了類似于“主謂賓”的易讀語法模式(如:assertThat(x,is(3));),使得代碼更加直觀、易讀。
assertThat 的基本語法如下:
assertThat( [value], [matcher statement] );
value :接下來想要測試的變量值;matcher statement :使用 Hamcrest 匹配符來表達的對前面變量所期望的值的聲明,如果 value 值與 matcher statement 所表達的期望值相符,則測試成功,否則測試失敗。
八、Postman與Spring Boot 單元測試的區(qū)別
Spring Boot的單元測試主要針對方法層面,可以測試Service層這類非對外暴露的接口的類中方法,并且可一次性批量測試多個方法、支持事務(wù)回滾。
Postman針對接口進行http測試,我平時這個比較多,創(chuàng)建的測試接口可保存、分類。
九、Postman基本用法
Postman是一款功能強大的網(wǎng)頁調(diào)試與發(fā)送網(wǎng)頁HTTP請求的工具。Postman能夠發(fā)送任何類型的HTTP請求(GET, HEAD, POST,PUT..),附帶任何數(shù)量的參數(shù)和HTTP headers。支持不同的認證機制(basic, digest,OAuth),接收到的響應(yīng)語法高亮(HTML,JSON或XML)。
安裝Postman
官方網(wǎng)站:
https://www.getpostman.com/apps

安裝后,Postman是介樣嬸兒滴~~??

往期推薦
