最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Springboot單元測(cè)試編寫實(shí)踐

 更新時(shí)間:2023年11月03日 08:26:17   作者:斜月86  
在日常的開發(fā)過程中,為了提高代碼的可靠性和健壯性,同時(shí)也是檢測(cè)代碼的質(zhì)量,減少測(cè)試環(huán)節(jié)的問題,會(huì)對(duì)完成的業(yè)務(wù)功能代碼編寫單元測(cè)試,在本文中,將分享一些單元測(cè)試的實(shí)踐和心得,需要的朋友可以參考下

1 前言

在日常的開發(fā)過程中,為了提高代碼的可靠性和健壯性,同時(shí)也是檢測(cè)代碼的質(zhì)量,減少測(cè)試環(huán)節(jié)的問題,會(huì)對(duì)完成的業(yè)務(wù)功能代碼編寫單元測(cè)試。有時(shí)間單元測(cè)試的覆蓋率也是工作的一部分。作者最近被安排了一項(xiàng)艱巨的單測(cè)任務(wù),在本文中,將分享一些單元測(cè)試的實(shí)踐和心得。

2 生成單元測(cè)試

通常情況下,單元測(cè)試都是使用 junit 編寫的,但是這種方式會(huì)真實(shí)的調(diào)用數(shù)據(jù),如何優(yōu)雅的實(shí)現(xiàn)單元測(cè)試是一個(gè)問題。這里使用的是 powermock 來實(shí)現(xiàn)測(cè)試用例的編寫。引入 powermock 依賴如下所示:

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.11.2</version>
    <scope>test</scope>
</dependency>

在編寫單元測(cè)試之前,需要在 idea 中安裝一個(gè) squaretest 插件,在需要編寫單元測(cè)試的類中,通過右鍵 generate -> generate Test 可以打開一個(gè)面板,可以選擇一個(gè)模板,就可以在test中生成具體的單元測(cè)試類。

可以這樣說,有了這個(gè)便捷的插件助力,對(duì)于簡(jiǎn)單的場(chǎng)景,就可以完全覆蓋其業(yè)務(wù)功能。

3 單測(cè)重點(diǎn)

雖然說通過 squaretest 可以實(shí)現(xiàn)大部分代碼的編寫,但是有一些場(chǎng)景還不能那么智能的實(shí)現(xiàn),需要編寫代碼實(shí)現(xiàn)功能。如下圖所示,除了第三個(gè)單測(cè)點(diǎn)外,其它的都是不常見的類型。

3.1 mock static 方法

static 方法的 mock 需要使用到 mockStatic 方法,具體的操作如下所示:

// 第一步需要在測(cè)試類上添加類名稱
@PrepareForTest(value = {類名.class})
// 第二步需要使用 mockStatic 聲明,然后進(jìn)行mock 操作
mockStatic(類名.class)
when(類名.static方法()).thenReturn(mock結(jié)果);

static 方法的 mock, 適用于需要加載系統(tǒng)配置或者初始化文件的場(chǎng)景,通過 mock 類的 static 方法,即可獲取相應(yīng)的返回值,避免類的初始化導(dǎo)致單元測(cè)試報(bào)錯(cuò)。

3.2 mock 分布式鎖

分布式鎖的 mock, 需要考慮的方面比較多,首先是根據(jù) redisclient 獲取分布式鎖,然后調(diào)用 tryLock 并等待加鎖的返回信息,這里其實(shí)是需要兩個(gè) mock, 但是 getLock 返回的 RLock 是一個(gè)接口,不能使用創(chuàng)建新類的方式來實(shí)現(xiàn),這里就需要使用 mock() 來創(chuàng)建一個(gè) RLock, 然后在其基礎(chǔ)上進(jìn)行 mock , 由此可以實(shí)現(xiàn)兩層的 mock。這里需要說明的是,分布式鎖使用的 Redisson 來實(shí)現(xiàn)的。

// mock RLock
RLock mock = mock(RLock.class);
// mock tryLock 和 getLock 兩個(gè)方法
when(mock.tryLock(anyLong(), eq(TimeUnit.MINUTES))).thenReturn(Boolean.TRUE);
when(mockRedisUtils.getLock(anyString())).thenReturn(mock);

3.3 mock spring 中的 bean

在單元測(cè)試中常用的 mock 即測(cè)試類中注入的 service、business、mapper 等內(nèi)容,通過 mock 所涉及的方法,以期得到對(duì)應(yīng)的返回值繼續(xù)業(yè)務(wù)流程的繼續(xù)。 when 和 thenReturn 需要組合使用,根據(jù)傳入的方法參數(shù)返回預(yù)期值。方法的入?yún)⒖梢允?any(), any(類.class), anyString(), anyInt(), anyLong() 等,但需要注意的是傳入的參數(shù)不能為 null,如果需要精確匹配,則需要使用 eq()。此外, thenReturn 的返回值可以有多個(gè),支持鏈?zhǔn)秸{(diào)用,如果返回值有多個(gè),則表示第一次調(diào)用方法返回第一個(gè)值,第二次調(diào)用方法返回第二個(gè)值,以此類推。另外,還有模擬方法調(diào)用發(fā)送異常的場(chǎng)景,則使用 doThrow 來返回對(duì)應(yīng)的異常。

// mock 業(yè)務(wù)查詢和操作
when(mockMapper.selectByUserId(eq("123"))).thenReturn(user);
when(mockMapper.selectByUserId(anyString())).thenReturn(user, user, user);
when(mockMapper.selectByUserId(anyString())).thenReturn(user).thenReturn(user).thenReturn(user);
when(mockMapper.updateById(any(User.class))).thenReturn(1);
// 模擬調(diào)用拋出異常
doThrow(RuntimeException.class).when(mockUserMapper).selectByUserId(anyString());

3.4 mock redis template 操作

對(duì)于 redis 的操作,其實(shí)和分布式鎖的操作類似,以操作字符串類型為例,需要先獲取一個(gè) opsForValue 而后來進(jìn)行操作 redisTemplate.opsForValue().方法,由于 ValueOperations 也是一個(gè)接口,所以需要使用 mock 來獲取一個(gè)操作對(duì)象,基于此在進(jìn)行 mock 所涉及的方法。

ValueOperations operations = mock(ValueOperations.class);
when(operations.increment(anyString())).thenReturn(230L);
when(redisTemplate.opsForValue()).thenReturn(operations);

3.5 mock 事務(wù) transactionTemplate

事務(wù)的操作是在特殊業(yè)務(wù)場(chǎng)景下才會(huì)用到,這里的只是借此場(chǎng)景來說明如何對(duì)匿名類中的方法進(jìn)行單測(cè)。默認(rèn)情況下生成的測(cè)試代碼是不具備這種能力的,需要使用 thenAnswer 來處理。以下列舉了兩種方式,一種是匿名類的方式,一種是 lambda 表達(dá)式的方法。根據(jù)以下方式操作,功能內(nèi)部類中代碼可以實(shí)現(xiàn)覆蓋。如果項(xiàng)目中使用了線程池,也同樣可以依據(jù)此方法處理。

// mock transaction
when(mockTransaction.execute(any(TransactionCallback.class))).thenReturn(true);
// 匿名內(nèi)部類
when(mockTransaction.execute(Mockito.<TransactionCallback>any())).thenAnswer(new Answer<Object>() {
    public Object answer(InvocationOnMock invocation) {
        Object[] args = invocation.getArguments();
        TransactionCallback arg = (TransactionCallback) args[0];
        return arg.doInTransaction(new SimpleTransactionStatus());
    }
});
// lambda 方式
Answer<Object> answer = invocation -> {
    Object[] args = invocation.getArguments();
    TransactionCallback arg = (TransactionCallback) args[0];
    return arg.doInTransaction(new SimpleTransactionStatus());
};
when(mockTransaction.execute(any())).thenAnswer(answer);

3.6 mock http ResetTemplate

通常情況下 http 的調(diào)用是使用 httpUtils 工具類, 但是特殊的情況下使用 restTemplate 進(jìn)行調(diào)用,如下所示,可以實(shí)現(xiàn)對(duì) http 調(diào)用的 mock,這里只是一種 post 的調(diào)用方式,如果有其他的類型調(diào)用可以參考編寫 mock

// mock http reset http
JSONObject body = new JSONObject();
body.put("code", "0000");
when(restTemplate.postForObject(anyString(), any(HttpEntity.class), eq(JSONObject.class))).thenReturn(body);

3.7 斷言

在編寫完成單元測(cè)試后,需要對(duì)結(jié)果進(jìn)行斷言,通常情況下每個(gè)方法都需要有一個(gè)斷言,針對(duì) void 方法,可以使用 verify 來進(jìn)行處理,校驗(yàn)方法中的某一個(gè)環(huán)節(jié)是否被處理過。現(xiàn)在項(xiàng)目的集成與發(fā)版都實(shí)現(xiàn)了自動(dòng)化,沒有斷言或者 verify 的方法會(huì)掃描出存在漏洞。斷言可以分為返回對(duì)象不為空或者返回值和預(yù)期值相同與否。verify 可以添加 times(1) 進(jìn)行測(cè)試,校驗(yàn)其方法調(diào)用的次數(shù)。

// 斷言返回對(duì)象不為空
Assert.assertNotNull(result);
// 斷言結(jié)果的期望值和結(jié)果值相同
Assert.assertEquals(result, expectedResult);
// 斷言方法中的某個(gè)環(huán)節(jié)被執(zhí)行過 調(diào)用一次
// times(n) 調(diào)用 n 次
// never() 沒有調(diào)用,相當(dāng)于 調(diào)用 0 次 times(0)
// atMostOnce() 最多調(diào)用一次
// atLeastOnce() 最少調(diào)用一次
// atLeast() 最少一次
// atMost() 最多一次
verify(mockUserMapper, times(2)).selectByUserId(anyString());
verify(mockUserMapper, atLeast(1)).selectByUserId(anyString());

3.8 異常用例

以上講述的都是正常的單測(cè),在實(shí)際的業(yè)務(wù)中還要模擬一些異常的場(chǎng)景,所以需要異常用例的編寫也是需要的,這樣進(jìn)入到異常場(chǎng)景也可以提高單測(cè)的覆蓋率。

// 單測(cè)期望拋出一個(gè)異常信息
@Test(expected = RuntimeException.class)
public void testMockTest_TransactionTemplateThrowsTransactionException() throws Exception {
 ...
 // 異常操作      
when(mockTransaction.execute(any(TransactionCallback.class))).thenThrow(RuntimeException.class);
  ....
}

3.9 測(cè)試類的 setUp

通常情況下,在復(fù)雜的業(yè)務(wù)場(chǎng)景,需要對(duì)測(cè)試類設(shè)置屬性值,一般情況下屬性值都是從配置文件讀取,那怎么對(duì)其設(shè)置屬性值呢?這里用到了反射的知識(shí),通過 hutool 工具類,可以對(duì)類的某個(gè)屬性賦值。同時(shí)也可以在這里做一些初始化的操作或者測(cè)試類單測(cè)前的準(zhǔn)備工作。

@Before
public void setUp() {
    initMocks(this);
    // 使用反射的方式設(shè)置對(duì)象屬性的值
    ReflectionTestUtils.setField(mockBusinessUnderTest, "name", "test");
}

4 總結(jié)

在本文中,主要介紹了編寫單元測(cè)試的實(shí)踐,通過 squaretest 插件可以解決大部分的測(cè)試場(chǎng)景,如果有測(cè)試覆蓋不到的地方,無外乎以上介紹的幾種特殊的場(chǎng)景。掌握了以上的方式,可以很輕松的將單測(cè)覆蓋率提高到一個(gè)比較高的水平。

以上就是Springboot單元測(cè)試編寫實(shí)踐的詳細(xì)內(nèi)容,更多關(guān)于Springboot單元測(cè)試的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java final關(guān)鍵字用法、場(chǎng)景、面試題全解析

    Java final關(guān)鍵字用法、場(chǎng)景、面試題全解析

    本文全程圍繞final的核心用法展開,從“修飾變量、修飾方法、修飾類”三個(gè)核心場(chǎng)景,搭配實(shí)戰(zhàn)代碼、避坑細(xì)節(jié),再補(bǔ)充高頻面試題,幫你徹底吃透final,既適合新手入門,也適合鞏固基礎(chǔ)、備戰(zhàn)面試,感興趣的朋友一起看看吧
    2026-04-04
  • JAVA生成xml文件簡(jiǎn)單示例

    JAVA生成xml文件簡(jiǎn)單示例

    這篇文章主要介紹了JAVA生成xml文件的相關(guān)資料,在Java中可以使用DOM或者JDOM來生成XML文件,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • Spring Boot 事務(wù)詳解(事務(wù)傳播行為、事務(wù)屬性)

    Spring Boot 事務(wù)詳解(事務(wù)傳播行為、事務(wù)屬性)

    Spring Boot 提供了強(qiáng)大的事務(wù)管理功能,通過 @Transactional 注解可以方便地配置事務(wù)的傳播行為和屬性,本文將詳細(xì)介紹 Spring Boot 中的事務(wù)管理,包括事務(wù)傳播行為、事務(wù)屬性以及聲明式和編程式事務(wù)管理,感興趣的朋友一起看看吧
    2025-05-05
  • mybatis-plus中配置日志信息方式

    mybatis-plus中配置日志信息方式

    這篇文章主要介紹了mybatis-plus中配置日志信息方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • SpringBoot解析JSON報(bào)錯(cuò)400 Bad Request的解決方案

    SpringBoot解析JSON報(bào)錯(cuò)400 Bad Request的解決方案

    在Spring Boot開發(fā)中,400 Bad Request錯(cuò)誤是常見的客戶端錯(cuò)誤之一,本文將從問題分析,排查步驟到解決方案進(jìn)行系統(tǒng)性講解,幫助開發(fā)者高效定位并修復(fù)問題
    2025-07-07
  • Java中啟動(dòng)線程start和run的兩種方法

    Java中啟動(dòng)線程start和run的兩種方法

    start()方法它的作用是啟動(dòng)一個(gè)新線程,run()就和普通的成員方法一樣,可以被重復(fù)調(diào)用。接下來通過本文給大家分享Java中啟動(dòng)線程start和run的兩種方法,需要的朋友參考下吧
    2017-11-11
  • java實(shí)現(xiàn)創(chuàng)建縮略圖、伸縮圖片比例生成的方法

    java實(shí)現(xiàn)創(chuàng)建縮略圖、伸縮圖片比例生成的方法

    這篇文章主要介紹了java實(shí)現(xiàn)創(chuàng)建縮略圖、伸縮圖片比例生成的方法,可實(shí)現(xiàn)針對(duì)圖片大小的縮放功能,是Java針對(duì)圖片操作的典型應(yīng)用,需要的朋友可以參考下
    2014-11-11
  • maven 中relativePath標(biāo)簽的作用

    maven 中relativePath標(biāo)簽的作用

    元素在 Maven 的 pom.xml 文件中用于指定父項(xiàng)目的相對(duì)路徑,這篇文章主要介紹了maven 中relativePath標(biāo)簽的作用,需要的朋友可以參考下
    2024-11-11
  • Java實(shí)現(xiàn)讀寫文件功能的代碼分享

    Java實(shí)現(xiàn)讀寫文件功能的代碼分享

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語言實(shí)現(xiàn)讀寫文件功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-08-08
  • SpringBoot實(shí)現(xiàn)短信發(fā)送及手機(jī)驗(yàn)證碼登錄

    SpringBoot實(shí)現(xiàn)短信發(fā)送及手機(jī)驗(yàn)證碼登錄

    本文主要介紹了SpringBoot實(shí)現(xiàn)短信發(fā)送及手機(jī)驗(yàn)證碼登錄,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07

最新評(píng)論

清徐县| 洪雅县| 潢川县| 柳江县| 会同县| 苍溪县| 含山县| 石泉县| 泗洪县| 宁安市| 虹口区| 营口市| 嘉兴市| 广东省| 确山县| 开封县| 保康县| 孝感市| 高唐县| 漳浦县| 长治市| 麻城市| 泽州县| 廊坊市| 精河县| 兴义市| 青田县| 新疆| 长汀县| 沙雅县| 宁国市| 中超| 无为县| 云南省| 大港区| 徐州市| 安仁县| 连平县| 武定县| 兴海县| 汾阳市|