不敢想象,你寫了3年程式,竟然很少寫單元測試!

2021-10-05 15:27:34 字數 3107 閱讀 9013

一、前言

有同學可能看到這個標題,又以為是標題黨了,你真莫笑,你可以小聲去問問你在中小型公司的同學,有多少在寫單測?可能有的同學就只知道junit,連mockito是什麼都不知道,希望本文能幫助你深入的了解單測框架。

相信做過開發的同學,都多多少少寫過下面的**,很長一段時間我一直以為這就是單元測試…

@springboottest

@runwith(springrunner.class)

public class unittest1 但這是單元測試嘛?unitservice 中可能還依賴了 dao 的操作;如果是微服務,可能還要起註冊中心。那麼這個「單元」也太大了吧!如果把它稱為整合測試,可能更恰當一點,那麼有沒有可能最小粒度進行單元測試嘛?

單元測試應該是乙個帶有隔離性的功能測試。在單元測試中,應盡量避免其他類或系統的***影響。

單元測試的目標是一小段**,例如方法或類。方法或類的外部依賴關係應從單元測試中移除,而改為測試框架建立的 mock 物件來替換依賴物件。

單元測試一般由開發人員編寫,通過驗證或斷言目標的一些行為或狀態來達到測試的目的。

二、junit 框架

junit 是乙個測試框架,它使用註解來標識測試方法。junit 是 github 上託管的乙個開源專案。

乙個 junit 測試指的是乙個包含在測試類中的方法,要定義某個方法為測試方法,請使用 @test 註解標註該方法。該方法執行被測**,可以使用 junit 或另乙個 assert 框架提供的 assert 方法來檢查預期結果與實際結果是否一致,這些方法呼叫通常稱為斷言或斷言語句。

public class unittest2 以下是一些常用的 junit 註解:

註解 描述

@test 將方法標識為測試方法

@before 在每次測試之前執行。用於準備測試環境(例如,讀取輸入資料,初始化類)

@after 每次測試之後執行。用於清理測試環境(例如,刪除臨時資料,恢復預設值)

@beforeclass 用於 static方法,在所有測試開始之前執行一次。它用於執行耗時的活動,例如:連線到資料庫

@afterclass 用於 static方法,在完成所有測試之後,執行一次。它用於執行清理活動,例如:與資料庫斷開連線

@ignore 指定要忽略的測試

@test(expected = exception.class) 如果該方法未引發命名異常,則失敗

@test(timeout=100) 如果該方法花費的時間超過100毫秒,則失敗

以下是一些常用的 assert 斷言:

宣告 描述

fail([message]) 使方法失敗。在執行測試**之前,可用於檢查未到達**的特定部分或測試失敗

asserttrue([message,]布林條件) 檢查布林條件是否為真

assertfalse([message,]布林條件) 檢查布林條件是否為假

assertequals([message,]預期,實際) 測試兩個值是否相同。注意:對於陣列,會檢查引用而不是陣列的內容

assertnull([message,]物件) 檢查物件是否為空

assertnotnull([message,]物件) 檢查物件是否不為空

assertsame([message,]預期,實際) 檢查兩個變數是否引用同一物件

assertnotsame([message,]預期,實際) 檢查兩個變數是否引用了不同的物件

三、mockito 框架

從上面的介紹我們可以認識到,如何減少對外部的依賴才是實踐單元測試的關鍵。而這正是 mockito 的使命,mockito 是乙個流行的 mock 框架,可以與 junit 結合使用,mockito 允許我們建立和配置 mock 物件,使用 mockito 將大大簡化了具有外部依賴項的類的測試開發。spring-boot-starter-test 中預設整合了 mockito,不需要額外引入。

在測試中使用 mockito,通常會:

mock 外部依賴關係並將 mock 物件插入待測**

執行被測**

驗證**是否正確執行

3.1 使用 mockito 建立 mock 物件

mockit o提供了幾種建立 mock 物件的方法:

使用靜態 mock() 方法

使用 @mock 註解

如果使用 @mock 註解,則必須觸發建立帶有 @mock 註解的物件。使用 mockitorule 可以做到,它通過呼叫靜態方法 mockitoannotations.initmocks(this) 來填充帶 @mock 註解的字段。或者可以使用 @runwith(mockitojunitrunner.class)。

public class unittest3 3.2 使用 mock 物件實踐單元測試

我們要單元測試的內容,常常包含著對資料庫的訪問等等,那麼我們要如何 mock 掉這部分呼叫呢?我們可以使用 @injectmocks 註解建立例項並使用 mock 物件進行依賴注入。

@service

public class unitserviceimpl implements unitservice }

@runwith(mockitojunitrunner.class)

public class unittest2 mockito 還有很多有趣的實踐,比如:@spy或spy()方法、verify()驗證等等,鑑於篇幅原因,讀者可自行挖掘。

3.3 使用 powermock mock 靜態方法。

mockito 也有一些侷限性。例如:不能 mock 靜態方法和私有方法。這個時候我們就要用到 powermock,powermock 支援 junit 和 testng,擴充套件了 easymock 和 mockito 框架,增加了mock static、final 方法的功能。

首先需要引入 powermock 的依賴:

org.powermock

powermock-module-junit4

2.0.7

test

org.powermock

powermock-api-mockito2

2.0.7

接下來就能愉快的 mock 靜態方法了。

@runwith(powermockrunner.class)

@preparefortest()

public class unittest4

想象五年之後的你

題注 無意間在網上看到這篇文章,給我主動很深。想想自己每年年初都給自己訂立了一些很詳細的目標,然而一年過去了,這些目標幾乎沒有達到的。很多時候就知道目標在那,但是覺得時間還很多,總是一拖再拖,到最後什麼也做不成。很讚賞這種倒推的思想,這也很值得我們很多人去實踐。當然無論目標多麼美好,無論計畫多麼周全...

想象5年之後的你

題注 無意間在網上看到這篇文章,憧憬著我的未來5年!一九七六年的冬天,當時我十九歲,在休斯頓太空總署的大空梭實驗室裡工作,同時也在總署旁邊的休斯頓大學主修電腦。縱然忙於學校 睡眠與工作之間,這幾乎佔據了我一天二十四小時的全部時間,但只要有多餘的一分鐘,我總是會把所有的精力放在我的 創作上。我知道寫歌...

想象五年之後的你

題注 無意間在網上看到這篇文章,給我主動很深。想想自己每年年初都給自己訂立了一些很詳細的目標,然而一年過去了,這些目標幾乎沒有達到的。很多時候就知道目標在那,但是覺得時間還很多,總是一拖再拖,到最後什麼也做不成。很讚賞這種倒推的思想,這也很值得我們很多人去實踐。當然無論目標多麼美好,無論計畫多麼周全...