一、前言
有同學可能看到這個標題,又以為是標題黨了,你真莫笑,你可以小聲去問問你在中小型公司的同學,有多少在寫單測?可能有的同學就只知道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年!一九七六年的冬天,當時我十九歲,在休斯頓太空總署的大空梭實驗室裡工作,同時也在總署旁邊的休斯頓大學主修電腦。縱然忙於學校 睡眠與工作之間,這幾乎佔據了我一天二十四小時的全部時間,但只要有多餘的一分鐘,我總是會把所有的精力放在我的 創作上。我知道寫歌...
想象五年之後的你
題注 無意間在網上看到這篇文章,給我主動很深。想想自己每年年初都給自己訂立了一些很詳細的目標,然而一年過去了,這些目標幾乎沒有達到的。很多時候就知道目標在那,但是覺得時間還很多,總是一拖再拖,到最後什麼也做不成。很讚賞這種倒推的思想,這也很值得我們很多人去實踐。當然無論目標多麼美好,無論計畫多麼周全...