Spring Boot 單元測(cè)試(Unit test)

一、 單元測(cè)試的概念

概念:

  1. 單元測(cè)試(unit testing),是指對(duì)軟件中的最小可測(cè)試單元進(jìn)行檢查和驗(yàn)證裸燎。在Java中單元測(cè)試的最小單元是類。
  2. 單元測(cè)試是開發(fā)者編寫的一小段代碼泼疑,用于檢驗(yàn)被測(cè)代碼的一個(gè)很小的德绿、很明確的功能是否正確。執(zhí)行單元測(cè)試退渗,就是為了證明這 段代碼的行為和我們期望是否一致移稳。

單元測(cè)試引用:

  1. 眾所周知,通過(guò)spring initialize創(chuàng)建的Spring Boot項(xiàng)目會(huì)在Maven中自動(dòng)攜帶很多starter依賴:

其中包含了一個(gè)名為spring-boot-starter-test的依賴会油,本文是圍繞這個(gè)依賴展開个粱。

  1. 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>

  1. spring-boot-starter-test有如下幾個(gè)庫(kù):

spring-boot-starter-testUML圖:

在這里插入圖片描述

序號(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ī):

  1. 保證或驗(yàn)證實(shí)現(xiàn)功能拉庵。
  2. 保護(hù)已經(jīng)實(shí)現(xiàn)的功能不被破壞。

三套蒂、Spring Boot引入的MockMvc的概念

  1. 什么是Mock?

在面向?qū)ο蟮某绦蛟O(shè)計(jì)中名段,模擬對(duì)象(英語(yǔ):mock object)是以可控的方式模擬真實(shí)對(duì)象行為的假對(duì)象。在編程過(guò)程中泣懊,通常通過(guò)模擬一些輸入數(shù)據(jù)伸辟,來(lái)驗(yàn)證程序是否達(dá)到預(yù)期結(jié)果。

  1. 為什么使用Mock對(duì)象馍刮?

使用模擬對(duì)象信夫,可以模擬復(fù)雜的、真實(shí)的對(duì)象行為卡啰。如果在單元測(cè)試中無(wú)法使用真實(shí)對(duì)象静稻,可采用模擬對(duì)象進(jìn)行替代。

  1. 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
  1. 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è)試的成員方法等:

圖一


圖二


建議第一個(gè)選項(xiàng)為Junit5

第三步:至此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)匯總一下:

  1. mockMvc.perform:執(zhí)行一個(gè)請(qǐng)求
  2. MockMvcRequestBuilders.get(“/XXX/get”):構(gòu)造一個(gè)請(qǐng)求,Post請(qǐng)求使用.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”):代表在報(bào)文頭添加一些必須的信息围苫,這里添加的是token
  6. ResultActions.andExpect:添加執(zhí)行完成后的斷言
  7. ResultActions.andExpect(MockMvcResultMatchers.status().isOk()):方法看請(qǐng)求的狀態(tài)響應(yīng)碼是否為200如果不是則拋異常裤园,測(cè)試不通過(guò)
  8. ResultActions.andDo:添加一個(gè)結(jié)果處理器,表示要對(duì)結(jié)果做點(diǎn)什么事情剂府,比如此處使用print():輸出整個(gè)響應(yīng)結(jié)果信息

六拧揽、斷言的概念

  1. 斷言(assert),是編程術(shù)語(yǔ)腺占,表示為一些布爾表達(dá)式淤袜,程序員相信在程序中的某個(gè)特定點(diǎn)該表達(dá)式值為真∷ゲ可以在任何時(shí)候啟用和禁用斷言驗(yàn)證铡羡,因此可以在測(cè)試時(shí)啟用斷言而在部署時(shí)禁用斷言。
  2. 使用斷言是判斷一個(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

image

安裝后,Postman是介樣?jì)饍旱蝵~??

在這里插入圖片描述
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末唁奢,一起剝皮案震驚了整個(gè)濱河市霎挟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌麻掸,老刑警劉巖酥夭,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異脊奋,居然都是意外死亡采郎,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門狂魔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蒜埋,“玉大人,你說(shuō)我怎么就攤上這事最楷≌荩” “怎么了待错?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)烈评。 經(jīng)常有香客問(wèn)我火俄,道長(zhǎng),這世上最難降的妖魔是什么讲冠? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任瓜客,我火速辦了婚禮,結(jié)果婚禮上竿开,老公的妹妹穿的比我還像新娘谱仪。我一直安慰自己,他們只是感情好否彩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布疯攒。 她就那樣靜靜地躺著,像睡著了一般列荔。 火紅的嫁衣襯著肌膚如雪敬尺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天贴浙,我揣著相機(jī)與錄音砂吞,去河邊找鬼。 笑死崎溃,一個(gè)胖子當(dāng)著我的面吹牛呜舒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播笨奠,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼袭蝗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了般婆?” 一聲冷哼從身側(cè)響起到腥,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蔚袍,沒(méi)想到半個(gè)月后乡范,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡啤咽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年晋辆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宇整。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瓶佳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鳞青,到底是詐尸還是另有隱情霸饲,我是刑警寧澤为朋,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站厚脉,受9級(jí)特大地震影響习寸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜傻工,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一霞溪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧中捆,春花似錦鸯匹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)幼东。三九已至臂容,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間根蟹,已是汗流浹背脓杉。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留简逮,地道東北人球散。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像散庶,于是被迫代替她去往敵國(guó)和親蕉堰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容