欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java Springboot 后端使用Mockito庫進行單元測試流程分析

 更新時間:2024年10月15日 11:27:52   作者:Bling_  
使用Mock進行單元測試可以避免啟動整個Spring框架,節(jié)省時間并降低外部依賴影響,Mock允許模擬外部方法和類,專注于測試方法的功能邏輯,本文給大家介紹Java Springboot 后端使用Mockito庫進行單元測試流程分析,感興趣的朋友跟隨小編一起看看吧

1 為什么要使用mock進行單元測試

如果使用SpringbootTest進行單元測試,那么將啟動spring服務(wù),生成容器和bean并加載所有外部資源或依賴,當工程量很大時啟動非常費時,顯然為了一個小小的單元測試啟動整個項目有一些大動干戈。

此外,有時部分外部依賴無法獲?。ㄈ鐢?shù)據(jù)庫連接、緩存或接口獲取有問題),而單元測試旨在測試某個類具體的方法,測試的是該方法的功能邏輯,不應(yīng)關(guān)注其依賴的對象,以防測試時各級方法互相調(diào)用太深(調(diào)用的方法應(yīng)該在它自己的單元測試中進行測試),相當于只關(guān)注測試方法的寬度而不在意它的深度。

因此,對于要測試的方法中使用到的外部類或方法,可以考慮使用模擬對象來模擬它們的調(diào)用并自定義好返回的值,這樣能夠在不執(zhí)行真實調(diào)用方法的同時讓單元測試正常進行,這就是mock的原理。使用mock可以很好的將要測試的方法和它的依賴分隔開,降低了模塊間的耦合,非常適合外部資源較難構(gòu)造或方法調(diào)用太深的場景。

2 使用mock的注意點

  • 通過mock進行單元測試時并未啟動spring,那么不會加載容器并生成bean,就無法通過自動注入的方式獲取依賴,需要使用mock注解
  • 如果測試的相關(guān)功能與spring有關(guān)(比如AOP),那么還是需要使用SpringbootTest
  • 啟用mock時可以看成啟動了普通的java項目,在普通項目中能運行的代碼在mock中也能運行
  • 單元測試時并非所有調(diào)用的外部方法或使用到的外部類都需要mock,如實體類可以直接new,工具類方法可以直接運行(不存在外部依賴的工具類,比如用來進行數(shù)據(jù)格式處理的工具類,通常調(diào)用其靜態(tài)方法),不需要使用mock

3 mock使用流程

3.1 測試前配置

使用mock首先需要在pom文件中導入相關(guān)依賴,然后可以使用@Mock或Mockito庫的mock方法來生成模擬對象,如果使用@Mock則需要先添加以下注解代碼:

  • 在測試類前添加@RunWith(MockitoJUnitRunner.class)@ExtendWith(MockitoExtension.class)
  • 在測試類內(nèi)添加如下方法:
//測試前準備,可以在這里進行一些基礎(chǔ)配置
@BeforeEach
    void setUp(){
        MockitoAnnotations.openMocks(this); //開啟mock,搭配@Mock使用
}

3.2 注入待測試類并模擬其中使用的變量

若需要測試的類為UserService,那么在它的測試類UserServiceTest中需要使用注解@InjectMocks注入UserService的實例,該注解的作用是自動創(chuàng)建并注入一個類的實例,同時將標記為@Mock的依賴注入到該實例中,注意@InjectMocks只能注入class。

@InjectMocks
UserService userService;

3.2.1 模擬成員變量

待測試類的成員變量需要使用@Mock注解注入,無法通過Mockito.mock()方法生成模擬對象,mock()方法生成的成員模擬對象在執(zhí)行時會報空指針錯誤,并未真正生成模擬對象。
UserService中有成員變量UserMapper,那么使用如下代碼注入:

@Mock
UserMapper

簡單來說就是將UserService里面的所有成員變量直接復制到Test里,然后將@Autowired改成@Mock即可。

3.2.2 模擬靜態(tài)對象

當代碼中需要調(diào)用某個類的靜態(tài)方法時,需要使用mockStatic()方法生成一個模擬靜態(tài)對象,如被測方法中若存在如下代碼:

DictUtil.getIns("A_END"); //DictUtil類中存在一些外部依賴,因此需要模擬

那么首先需要生成DictUtil的模擬靜態(tài)對象:

mockStatic(DictUtil.class);  //上下兩種寫法都可以
MockedStatic<DictUtil> dictUtilMockedStatic = mockStatic(DictUtil.class);

3.2.3 模擬普通變量

對于代碼中生成的一些中間變量,而在后期又需要使用這些變量進行方法調(diào)用時,需要先使用mock將中間變量模擬出,如被測方法中若存在代碼:

UserCache.getInstance().getName("12345");

那么需要先模擬出UserCache的一個實例(打樁時不能對連續(xù)調(diào)用的方法同時打樁,需先生成中間變量),此時可以使用@Mock或者mock方法:

// 1. 當成測試類成員變量注入
@Mock
UserCache userCache;
// 2. 在測試方法中直接模擬
UserCache userCache = Mockito.mock(UserCache.class);

3.3 打樁模擬方法調(diào)用行為

3.3.1 非靜態(tài)方法打樁

打樁即對調(diào)用的方法模擬傳參并設(shè)置返回值,參數(shù)個數(shù)和返回值需要與原方法對應(yīng)。打樁之后不會真正去調(diào)用,會忽略真實方法的執(zhí)行結(jié)果,一般使用Mockito.when().thenReturn()進行打樁。
若被測類方法中存在代碼:

User user = UserMapper.selectById("0000");

那么測試方法中的打樁可以是:

//實體類不需要mock,可以直接生成,然后使用setter方法賦值
User user = new User();
// 1. 固定了打樁參數(shù)為“0000”,源代碼調(diào)用中參數(shù)為非“0000”時打樁失敗
Mockito.when(UserMapper.selectById("0000")).thenReturn(user)
// 2. 為了代碼的健壯性,通常使用Mockito.anyxxx()方法來接收參數(shù),根據(jù)xxx的不同來指定不同的類型,只要是該類型的任意參數(shù)都可以打樁
Mockito.when(UserMapper.selectById(Mockito.anyString())).thenReturn(user)

3.3.2 靜態(tài)方法打樁

以原代碼UserCache.getInstance().getName("12345");為例,靜態(tài)方法打樁有兩種寫法:
1) 普通寫法

UserCache userCache = Mockito.mock(UserCache.class);
mockStatic(UserCache.class);  
Mockito.when(UserCache.getInstance()).thenReturn(userCache);
Mockito.when(userCache.getName(Mockito.anyString())).thenReturn("TestName");

2) lambda寫法-無參靜態(tài)方法調(diào)用

UserCache userCache = Mockito.mock(UserCache.class);
MockedStatic<UserCache> userCacheMockedStatic = mockStatic(UserCache.class);
//1. 當靜態(tài)方法無參時,可以使用::進行方法調(diào)用
userCacheMockedStatic.when(UserCache::getInstance).thenReturn(userCache);
//2. 也可以使用lambda寫法,使用.進行調(diào)用
userCacheMockedStatic.when(() -> UserCache.getInstance()).thenReturn(userCache);
//3. 不能使用如下寫法:
//userCacheMockedStatic.when(UserCache.getInstance()).thenReturn(userCache);
Mockito.when(userCache.getName(Mockito.anyString())).thenReturn("TestName");

3) lambda寫法-有參靜態(tài)方法調(diào)用
假如上述getInstance方法有一個int參數(shù),那么可以通過1)中的普通寫法進行打樁,或者使用2)-2的方式進行打樁,然后使用Mockito.anyString()傳參,但是不能使用2)-1或2)-3的寫法。

3.3.3 Maven test靜態(tài)模擬報錯問題

當單獨運行一個Test時沒有問題,但是當集體執(zhí)行Test時會出現(xiàn)如下報錯:

‘static mocking is already registered in the current thread To create a new mock, the existing static mock registration must be deregistered’

這是因為有兩個以上的測試方法都使用了同一個靜態(tài)mock對象,如兩個Test中都有MockedStatic<UserCache> userCacheMockedStatic = mockStatic(UserCache.class),而靜態(tài)mock對象不允許公用,因此需要在每個靜態(tài)mock對象執(zhí)行后對其進行關(guān)閉,下一個方法才能繼續(xù)使用它,故需要在每個Test末尾中寫:userCacheMockedStatic.close()
由于MockedStatic<T>的父接口繼承了AutoCloseable接口,因此可以使用 try-resources語句實現(xiàn)資源的自動關(guān)閉:

try(
	// mockStatic(UserCache.class);  //java8不支持這種寫法
	MockedStatic<UserCache> userCacheMockedStatic = mockStatic(UserCache.class);
	// ……其他靜態(tài)模擬對象聲明
){
    //其他測試代碼
}

也可以選擇用try-catch-finally在finally語句里手動關(guān)閉:

try(
	MockedStatic<UserCache> userCacheMockedStatic = mockStatic(UserCache.class);
	// ……其他測試代碼
)finally{
    userCacheMockedStatic.close();
}

3.4 斷言判斷測試結(jié)果

要檢測測試的結(jié)果,需要使用斷言Assertions進行判斷,根據(jù)實際測試要求來:

User user = UserService.getById("123");
User expectUsr = new User("123");
Assertions.assertEquals(expectUsr ,user)://判斷測試結(jié)果user與期望的對象是否一致
Assertions.assertNotNull(user)://判斷測試結(jié)果user是否非空

到此這篇關(guān)于Java Springboot 后端使用Mockito庫進行單元測試流程的文章就介紹到這了,更多相關(guān)Springboot Mockito單元測試內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳細講解Java的泛型

    詳細講解Java的泛型

    這篇文章主要介紹了Java的泛型,是Java入門學習中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • 詳解如何更改SpringBoot TomCat運行方式

    詳解如何更改SpringBoot TomCat運行方式

    這篇文章主要介紹了詳解如何更改SpringBoot TomCat運行方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • 線程阻塞喚醒工具 LockSupport使用詳解

    線程阻塞喚醒工具 LockSupport使用詳解

    這篇文章主要為大家介紹了線程阻塞喚醒工具LockSupport使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • Mybatis ResultType如何處理返回類型

    Mybatis ResultType如何處理返回類型

    這篇文章主要介紹了Mybatis ResultType如何處理返回類型方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Spring Cloud Gateway 默認的filter功能和執(zhí)行順序介紹

    Spring Cloud Gateway 默認的filter功能和執(zhí)行順序介紹

    這篇文章主要介紹了Spring Cloud Gateway 默認的filter功能和執(zhí)行順序,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java?@Accessors注解圖文詳解

    Java?@Accessors注解圖文詳解

    @Accessors用于改變@Data生成的getter和setter方法的生成結(jié)果,下面這篇文章主要給大家介紹了關(guān)于Java?@Accessors注解的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • intellij idea的快速配置使用詳細教程

    intellij idea的快速配置使用詳細教程

    這篇文章主要介紹了intellij idea的快速配置使用詳細教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • SpringBoot2.3新特性優(yōu)雅停機詳解

    SpringBoot2.3新特性優(yōu)雅停機詳解

    這篇文章主要介紹了SpringBoot2.3新特性優(yōu)雅停機詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-05-05
  • 淺談Java中的this作為返回值時返回的是什么

    淺談Java中的this作為返回值時返回的是什么

    Java中的this作為返回值時返回的是什么?下面小編就為大家介紹一下Java中的this作為返回值時返回。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • 解讀thymeleaf模板引擎中th:if的使用

    解讀thymeleaf模板引擎中th:if的使用

    這篇文章主要介紹了解讀thymeleaf模板引擎中th:if的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10

最新評論