一、 單元測(cè)試的概念
概念:
- 單元測(cè)試(unit testing),是指對(duì)軟件中的最小可測(cè)試單元進(jìn)行檢查和驗(yàn)證裸燎。在Java中單元測(cè)試的最小單元是類。
- 單元測(cè)試是開發(fā)者編寫的一小段代碼泼疑,用于檢驗(yàn)被測(cè)代碼的一個(gè)很小的德绿、很明確的功能是否正確。執(zhí)行單元測(cè)試退渗,就是為了證明這 段代碼的行為和我們期望是否一致移稳。
單元測(cè)試引用:
- 眾所周知,通過(guò)
spring initialize
創(chuàng)建的Spring Boot項(xiàng)目會(huì)在Maven中自動(dòng)攜帶很多starter依賴:
其中包含了一個(gè)名為spring-boot-starter-test
的依賴会油,本文是圍繞這個(gè)依賴展開个粱。
- Spring Boot中引入單元測(cè)試很簡(jiǎn)單,添加如下依賴(即
spring-boot-starter-test
依賴):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
- spring-boot-starter-test有如下幾個(gè)庫(kù):
spring-boot-starter-test
UML圖:
序號(hào) | 庫(kù)名的解釋 |
---|---|
1 | JUnit 5:包含兼容 JUnit 4翻翩,Java 應(yīng)用程序單元測(cè)試的事實(shí)標(biāo)準(zhǔn) |
2 | Spring Test 和 SpringBootTest:對(duì)Spring Boot應(yīng)用程序的公共和集成測(cè)試支持 |
3 | AssertJ:流式斷言庫(kù) |
4 | Hamcrest:匹配對(duì)象庫(kù) |
5 | Mockito:Java 模擬框架 |
6 | JSONassert:JSON 斷言庫(kù) |
7 | JsonPath:JSON XPath |
二都许、單元測(cè)試的作用
在沒(méi)有接觸單元測(cè)試之前我們是怎么做測(cè)試的?一般有兩個(gè)方法:
方法 | 弊端 |
---|---|
方法一:啟動(dòng)整個(gè)應(yīng)用嫂冻,像用戶正常操作一樣胶征。點(diǎn)擊界面按鈕,調(diào)用一個(gè) API 等桨仿。 | 每次測(cè)試都要啟動(dòng)整個(gè)項(xiàng)目 |
方法二:在代碼某個(gè)地方寫一個(gè)臨時(shí)入口睛低,例如 java 的 main 方法,測(cè)試某個(gè)方法或者某個(gè)類。 | 入口用完要?jiǎng)h除钱雷,不然會(huì)影響項(xiàng)目的運(yùn)行速度或效率 |
在時(shí)間允許的情況下骂铁,編寫單元測(cè)試是程序員對(duì)代碼的自測(cè),這是對(duì)自己代碼的負(fù)責(zé)罩抗。
寫單元測(cè)試的兩個(gè)動(dòng)機(jī):
- 保證或驗(yàn)證實(shí)現(xiàn)功能拉庵。
- 保護(hù)已經(jīng)實(shí)現(xiàn)的功能不被破壞。
三套蒂、Spring Boot引入的MockMvc的概念
- 什么是Mock?
在面向?qū)ο蟮某绦蛟O(shè)計(jì)中名段,模擬對(duì)象(英語(yǔ):mock object)是以可控的方式模擬真實(shí)對(duì)象行為的假對(duì)象。在編程過(guò)程中泣懊,通常通過(guò)模擬一些輸入數(shù)據(jù)伸辟,來(lái)驗(yàn)證程序是否達(dá)到預(yù)期結(jié)果。
- 為什么使用Mock對(duì)象馍刮?
使用模擬對(duì)象信夫,可以模擬復(fù)雜的、真實(shí)的對(duì)象行為卡啰。如果在單元測(cè)試中無(wú)法使用真實(shí)對(duì)象静稻,可采用模擬對(duì)象進(jìn)行替代。
- MockMvc的概念
MockMvc是由spring-test包提供匈辱,實(shí)現(xiàn)了對(duì)Http請(qǐng)求的模擬振湾,能夠直接使用網(wǎng)絡(luò)的形式,轉(zhuǎn)換到Controller的調(diào)用亡脸,使得測(cè)試速度快押搪、不依賴網(wǎng)絡(luò)環(huán)境。同時(shí)提供了一套驗(yàn)證的工具浅碾,結(jié)果的驗(yàn)證十分方便大州。
接口MockMvcBuilder,提供一個(gè)唯一的build方法垂谢,用來(lái)構(gòu)造MockMvc厦画。主要有兩個(gè)實(shí)現(xiàn):StandaloneMockMvcBuilder和DefaultMockMvcBuilder。
實(shí)例化方法 | 實(shí)例&解釋 |
---|---|
方法一 | mockMvc = MockMvcBuilders.standaloneSetup(new HelloWorldController()).build();通過(guò)參數(shù)指定一組控制器滥朱,這樣就不需要從上下文獲取了 |
方法二 | mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();指定WebApplicationContext根暑,將會(huì)從該上下文獲取相應(yīng)的控制器并得到相應(yīng)的MockMvc |
- MockMVC的基本步驟
(1) mockMvc.perform執(zhí)行一個(gè)請(qǐng)求。
(2) MockMvcRequestBuilders.get(“XXX”)構(gòu)造一個(gè)請(qǐng)求徙邻。
(3) ResultActions.param添加請(qǐng)求傳值
(4) ResultActions.accept()設(shè)置返回類型
(5) ResultActions.andExpect添加執(zhí)行完成后的斷言排嫌。
(6) ResultActions.andDo添加一個(gè)結(jié)果處理器,表示要對(duì)結(jié)果做點(diǎn)什么事情鹃栽,比如處使用print()輸出整個(gè)響應(yīng)結(jié)果信息躏率。
(7) ResultActions.andReturn表示執(zhí)行完成后返回相應(yīng)的結(jié)果。
四民鼓、Service層的單元測(cè)試
(以下圖片均引自文末學(xué)習(xí)文章薇芝,因?yàn)楣卷?xiàng)目不方便截圖)
第一步:Spring Boot中單元測(cè)試類寫在src/test/java目錄下,你可以手動(dòng)創(chuàng)建具體測(cè)試類丰嘉,也可以通過(guò)IDEA自動(dòng)創(chuàng)建測(cè)試類夯到,如下圖:(注:雙擊打開相應(yīng)代碼的編輯器頁(yè)面,再點(diǎn)擊菜單欄的Navigate可以看到Test菜單)
或者編輯器里面在類名的右鍵菜單饮亏,點(diǎn)擊
Go To-->Test
即可耍贾。第二步:按照第一步的方法,點(diǎn)擊測(cè)試后路幸,出現(xiàn)圖一的對(duì)話框(如果想要測(cè)試的類已經(jīng)存在測(cè)試類了會(huì)被列出來(lái)荐开,也可以重新創(chuàng)建一個(gè)新的測(cè)試類),點(diǎn)擊”Create New Test…”會(huì)彈出圖二的對(duì)話框简肴,可以選擇是否生成setUp以及要測(cè)試的成員方法等:
圖一
圖二
第三步:至此Service層的測(cè)試類就創(chuàng)建好了晃听,測(cè)試類自動(dòng)生成到了src/test/java目錄下<u style="box-sizing: border-box; outline: 0px; overflow-wrap: break-word;">項(xiàng)目的同級(jí)目錄中</u>,如下圖:
Service層測(cè)試代碼如下:
@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
:獲取啟動(dòng)類砰识,加載配置能扒,尋找主配置啟動(dòng)類(被 @SpringBootApplication 注解的) @RunWith(SpringRunner.class)
:讓JUnit運(yùn)行Spring的測(cè)試環(huán)境,獲得Spring環(huán)境的上下文的支持
五、Controller層的單元測(cè)試
創(chuàng)建測(cè)試類步驟見第四部分辫狼,此處略初斑。
- 第四部分只是針對(duì)Service層做了測(cè)試,但是咱么也需要對(duì)Controller層(API)做測(cè)試膨处,這時(shí)候就用到MockMvc了见秤,它使得你無(wú)需啟動(dòng)項(xiàng)目工程就能測(cè)試這些接口。
- MockMvc實(shí)現(xiàn)了對(duì)Http請(qǐng)求的模擬真椿,能夠直接使用網(wǎng)絡(luò)的形式秦叛,轉(zhuǎn)換到Controller的調(diào)用,這樣可以使得測(cè)試速度快瀑粥、不依賴網(wǎng)絡(luò)環(huán)境挣跋,而且提供了一套驗(yàn)證的工具,這樣可以使得請(qǐng)求的驗(yàn)證統(tǒng)一而且很方便狞换。
Controller層部分的代碼小名將分為三個(gè)代碼塊講解避咆,里面有看不懂的代碼先不要著急哦??,小名會(huì)在第五部分結(jié)尾處給大家匯總解答的修噪,大家要堅(jiān)持看到最后喲查库!??
代碼塊一:
@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
>:獲取啟動(dòng)類,加載配置黄琼,尋找主配置啟動(dòng)類(被 @SpringBootApplication 注解的)
@RunWith(SpringRunner.class)
>:讓JUnit運(yùn)行Spring的測(cè)試環(huán)境,獲得Spring環(huán)境的上下文的支持 @AutoConfigureMockMvc
:用于自動(dòng)配置MockMvc,配置后MockMvc類可以直接注入,相當(dāng)于new MockMvc @Before
:初始化方法 ,對(duì)于每一個(gè)測(cè)試方法都要執(zhí)行一次
代碼塊二:
@Test
@Transactional
@Rollback()
public void save() throws Exception {
String json"{……}";
//執(zhí)行一個(gè)RequestBuilder請(qǐng)求樊销,會(huì)自動(dòng)執(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ù)回滾,默認(rèn)是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
運(yùn)行結(jié)果如下:
現(xiàn)在小名將上面的一些瑣碎的知識(shí)點(diǎn)匯總一下:
-
mockMvc.perform
:執(zhí)行一個(gè)請(qǐng)求 -
MockMvcRequestBuilders.get(“/XXX/get”)
:構(gòu)造一個(gè)請(qǐng)求,Post請(qǐng)求使用.post方法 -
contentType(MediaType.APPLICATION_JSON_VALUE)
:代表發(fā)送端發(fā)送的數(shù)據(jù)格式是application/json;charset=UTF-8 -
accept(MediaType.APPLICATION_JSON)
:代表客戶端希望接受的數(shù)據(jù)類型為application/json;charset=UTF-8 -
header(“Authorization”,“Bearer XXXX”)
:代表在報(bào)文頭添加一些必須的信息围苫,這里添加的是token -
ResultActions.andExpect
:添加執(zhí)行完成后的斷言 -
ResultActions.andExpect(MockMvcResultMatchers.status().isOk())
:方法看請(qǐng)求的狀態(tài)響應(yīng)碼是否為200如果不是則拋異常裤园,測(cè)試不通過(guò) -
ResultActions.andDo
:添加一個(gè)結(jié)果處理器,表示要對(duì)結(jié)果做點(diǎn)什么事情剂府,比如此處使用print():輸出整個(gè)響應(yīng)結(jié)果信息
六拧揽、斷言的概念
- 斷言(assert),是編程術(shù)語(yǔ)腺占,表示為一些布爾表達(dá)式淤袜,程序員相信在程序中的某個(gè)特定點(diǎn)該表達(dá)式值為真∷ゲ可以在任何時(shí)候啟用和禁用斷言驗(yàn)證铡羡,因此可以在測(cè)試時(shí)啟用斷言而在部署時(shí)禁用斷言。
- 使用斷言是判斷一個(gè)函數(shù)或?qū)ο蟮囊粋€(gè)方法所產(chǎn)生的結(jié)果是否符合你期望的那個(gè)結(jié)果意鲸。
七蓖墅、新斷言assertThat使用
JUnit 4.4 結(jié)合 Hamcrest 提供了一個(gè)全新的斷言語(yǔ)法——assertThat。程序員可以只使用 assertThat 一個(gè)斷言語(yǔ)句临扮,結(jié)合 Hamcrest 提供的匹配符论矾,就可以表達(dá)全部的測(cè)試思想。
assertThat 的優(yōu)點(diǎn):
優(yōu)點(diǎn) 1:以前 JUnit 提供了很多的 assertion 語(yǔ)句杆勇,如:assertEquals贪壳,assertNotSame,assertFalse蚜退,assertTrue闰靴,assertNotNull,assertNull 等钻注,現(xiàn)在有了 JUnit 4.4蚂且,一條 assertThat 即可以替代所有的 assertion 語(yǔ)句,這樣可以在所有的單元測(cè)試中只使用一個(gè)斷言方法幅恋,使得編寫測(cè)試用例變得簡(jiǎn)單杏死,代碼風(fēng)格變得統(tǒng)一,測(cè)試代碼也更容易維護(hù)捆交。
優(yōu)點(diǎn) 2:assertThat 使用了 Hamcrest 的 Matcher 匹配符淑翼,用戶可以使用匹配符規(guī)定的匹配準(zhǔn)則精確的指定一些想設(shè)定滿足的條件,具有很強(qiáng)的易讀性品追,而且使用起來(lái)更加靈活玄括。
優(yōu)點(diǎn) 3:assertThat 不再像 assertEquals 那樣,使用比較難懂的“謂賓主”語(yǔ)法模式(如:assertEquals(3, x);)肉瓦,相反遭京,assertThat 使用了類似于“主謂賓”的易讀語(yǔ)法模式(如:assertThat(x,is(3));)胃惜,使得代碼更加直觀、易讀哪雕。
assertThat 的基本語(yǔ)法如下:
assertThat( [value], [matcher statement] );
value :接下來(lái)想要測(cè)試的變量值船殉; matcher statement :使用 Hamcrest 匹配符來(lái)表達(dá)的對(duì)前面變量所期望的值的聲明,如果 value 值與 matcher statement 所表達(dá)的期望值相符热监,則測(cè)試成功,否則測(cè)試失敗饮寞。
八孝扛、Postman與Spring Boot 單元測(cè)試的區(qū)別
- Spring Boot的單元測(cè)試主要針對(duì)方法層面,可以測(cè)試Service層這類非對(duì)外暴露的接口的類中方法幽崩,并且可一次性批量測(cè)試多個(gè)方法苦始、支持事務(wù)回滾。
- Postman針對(duì)接口進(jìn)行http測(cè)試慌申,我平時(shí)這個(gè)比較多陌选,創(chuàng)建的測(cè)試接口可保存、分類蹄溉。
九咨油、Postman基本用法
Postman是一款功能強(qiáng)大的網(wǎng)頁(yè)調(diào)試與發(fā)送網(wǎng)頁(yè)HTTP請(qǐng)求的工具。Postman能夠發(fā)送任何類型的HTTP請(qǐng)求(GET, HEAD, POST,PUT..)柒爵,附帶任何數(shù)量的參數(shù)和HTTP headers役电。支持不同的認(rèn)證機(jī)制(basic, digest,OAuth),接收到的響應(yīng)語(yǔ)法高亮(HTML棉胀,JSON或XML)法瑟。
安裝Postman 官方網(wǎng)站:https://www.getpostman.com/apps
安裝后,Postman是介樣?jì)饍旱蝵~??