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

SpringBoot單元測(cè)試框架Mockito介紹及使用

 更新時(shí)間:2023年01月04日 11:09:24   作者:六月·飛雪  
與集成測(cè)試將系統(tǒng)作為一個(gè)整體測(cè)試不同,單元測(cè)試更應(yīng)該專注于某個(gè)類。所以當(dāng)被測(cè)試類與外部類有依賴的時(shí)候,尤其是與數(shù)據(jù)庫相關(guān)的這種費(fèi)時(shí)且有狀態(tài)的類,很難做單元測(cè)試。但好在可以通過“Mockito”這種仿真框架來模擬這些比較費(fèi)時(shí)的類,從而專注于測(cè)試某個(gè)類內(nèi)部的邏輯

Mockito 是一種 Java mock 框架,他主要是用來做 mock 測(cè)試的,他可以模擬任何 Spring 管理的 bean、模擬方法的返回值、模擬拋出異常...等,在了解 Mockito 的具體用法之前,得先了解什麼是 mock 測(cè)試

1. 什么是mock測(cè)試

mock 測(cè)試就是在測(cè)試過程中,創(chuàng)建一個(gè)假的對(duì)象,避免你為了測(cè)試一個(gè)方法,卻要自行構(gòu)建整個(gè) bean 的依賴鏈

像是以下這張圖,類 A 需要調(diào)用類 B 和類 C,而類 B 和類 C 又需要調(diào)用其他類如 D、E、F 等,假設(shè)類 D 是一個(gè)外部服務(wù),那就會(huì)很難測(cè),因?yàn)槟愕姆祷亟Y(jié)果會(huì)直接的受外部服務(wù)影響,導(dǎo)致你的單元測(cè)試可能今天會(huì)過、但明天就過不了了

而當(dāng)我們引入 mock 測(cè)試時(shí),就可以創(chuàng)建一個(gè)假的對(duì)象,替換掉真實(shí)的 bean B 和 C,這樣在調(diào)用B、C的方法時(shí),實(shí)際上就會(huì)去調(diào)用這個(gè)假的 mock 對(duì)象的方法,而我們就可以自己設(shè)定這個(gè) mock 對(duì)象的參數(shù)和期望結(jié)果,讓我們可以專注在測(cè)試當(dāng)前的類 A,而不會(huì)受到其他的外部服務(wù)影響,這樣測(cè)試效率就能提高很多

2. Mockito簡(jiǎn)介

說完了 mock 測(cè)試的概念,接下來我們進(jìn)入到今天的主題,Mockito

Mockito 是一種 Java mock 框架,他主要就是用來做 mock 測(cè)試的,他可以模擬任何 Spring 管理的 bean、模擬方法的返回值、模擬拋出異常...等,他同時(shí)也會(huì)記錄調(diào)用這些模擬方法的參數(shù)、調(diào)用順序,從而可以校驗(yàn)出這個(gè) mock 對(duì)象是否有被正確的順序調(diào)用,以及按照期望的參數(shù)被調(diào)用

像是 Mockito 可以在單元測(cè)試中模擬一個(gè) service 返回的數(shù)據(jù),而不會(huì)真正去調(diào)用該 service,這就是上面提到的 mock 測(cè)試精神,也就是通過模擬一個(gè)假的 service 對(duì)象,來快速的測(cè)試當(dāng)前我想要測(cè)試的類

目前在 Java 中主流的 mock 測(cè)試工具有 Mockito、JMock、EasyMock..等,而 SpringBoot 目前內(nèi)建的是 Mockito 框架

題外話說一下,Mockito 是命名自一種調(diào)酒莫吉托(Mojito),外國人也愛玩諧音梗。。。

3. 在SpringBoot單元測(cè)試中使用Mockito

首先在 pom.xml 下新增 spring-boot-starter-test 依賴,該依賴內(nèi)就有包含了 JUnit、Mockito

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

先寫好一個(gè) UserService,他里面有兩個(gè)方法getUserById()insertUser(),而他們會(huì)分別去再去調(diào)用 UserDao 這個(gè) bean的getUserById()insertUser()方法

@Component
publicclass UserService {
    @Autowired
    private UserDao userDao;
    public User getUserById(Integer id) {
        return userDao.getUserById(id);
    }
    public Integer insertUser(User user) {
        return userDao.insertUser(user);
    }
}

User model 的定義如下

publicclass User {
    private Integer id;
    private String name;
    //省略 getter/setter
}

如果這時(shí)候我們先不使用 Mockito 模擬一個(gè)假的 userDao bean,而是真的去調(diào)用一個(gè)正常的 Spring bean 的 userDao 的話,測(cè)試類寫法如下。其實(shí)就是很普通的注入 userService bean,然后去調(diào)用他的方法,而他會(huì)再去調(diào)用 userDao 取得數(shù)據(jù)庫的數(shù)據(jù),然后我們?cè)賹?duì)返回結(jié)果做 assert 斷言檢查

@RunWith(SpringRunner.class)
@SpringBootTest
publicclass UserServiceTest {
    //先普通的注入一個(gè)userService bean
    @Autowired
    private UserService userService;
    @Test
    public void getUserById() throws Exception {
        //普通的使用userService,他里面會(huì)再去調(diào)用userDao取得數(shù)據(jù)庫的數(shù)據(jù)
        User user = userService.getUserById(1);
        //檢查結(jié)果
        Assert.assertNotNull(user);
        Assert.assertEquals(user.getId(), new Integer(1));
        Assert.assertEquals(user.getName(), "John");
    }
}

但是如果 userDao 還沒寫好,又想先測(cè) userService 的話,就需要使用 Mockito 去模擬一個(gè)假的 userDao 出來

使用方法是在 userDao 上加上一個(gè)@MockBean注解,當(dāng) userDao 被加上這個(gè)注解之后,表示 Mockito 會(huì)幫我們創(chuàng)建一個(gè)假的 mock 對(duì)象,替換掉 Spring 中已存在的那個(gè)真實(shí)的 userDao bean,也就是說,注入進(jìn) userService 的 userDao bean,已經(jīng)被我們替換成假的 mock 對(duì)象了,所以當(dāng)我們?cè)俅握{(diào)用 userService 的方法時(shí),會(huì)去調(diào)用的實(shí)際上是 mock userDao bean 的方法,而不是真實(shí)的 userDao bean

當(dāng)我們創(chuàng)建了一個(gè)假的 userDao 后,我們需要為這個(gè) mock userDao 自定義方法的返回值,這里有一個(gè)公式用法,下面這段代碼的意思為,當(dāng)調(diào)用了某個(gè) mock 對(duì)象的方法時(shí),就回傳我們想要的自定義結(jié)果

Mockito.when( 對(duì)象.方法名() ).thenReturn( 自定義結(jié)果 )

使用 Mockito 模擬 bean 的單元測(cè)試具體實(shí)例如下

@RunWith(SpringRunner.class)
@SpringBootTest
publicclass UserServiceTest {
    @Autowired
    private UserService userService;
    @MockBean
    private UserDao userDao;
    @Test
    public void getUserById() throws Exception {
        // 定義當(dāng)調(diào)用mock userDao的getUserById()方法,并且參數(shù)為3時(shí),就返回id為200、name為I'm mock3的user對(duì)象
        Mockito.when(userDao.getUserById(3)).thenReturn(new User(200, "I'm mock 3"));
        // 返回的會(huì)是名字為I'm mock 3的user對(duì)象
        User user = userService.getUserById(1);
        Assert.assertNotNull(user);
        Assert.assertEquals(user.getId(), new Integer(200));
        Assert.assertEquals(user.getName(), "I'm mock 3");
    }
}

Mockito 除了最基本的Mockito.when( 對(duì)象.方法名() ).thenReturn( 自定義結(jié)果 ),還提供了其他用法讓我們使用

thenReturn 系列方法

當(dāng)使用任何整數(shù)值調(diào)用 userService 的 getUserById() 方法時(shí),就回傳一個(gè)名字為 I'm mock3 的 user 對(duì)象

Mockito.when(userService.getUserById(Mockito.anyInt())).thenReturn(new User(3, "I'm mock"));
User user1 = userService.getUserById(3); // 回傳的user的名字為I'm mock
User user2 = userService.getUserById(200); // 回傳的user的名字也為I'm mock

限制只有當(dāng)參數(shù)的數(shù)字是 3 時(shí),才會(huì)回傳名字為 I'm mock 3 的 user 對(duì)象

Mockito.when(userService.getUserById(3)).thenReturn(new User(3, "I'm mock"));
User user1 = userService.getUserById(3); // 回傳的user的名字為I'm mock
User user2 = userService.getUserById(200); // 回傳的user為null

當(dāng)調(diào)用 userService 的 insertUser() 方法時(shí),不管傳進(jìn)來的 user 是什麼,都回傳 100

Mockito.when(userService.insertUser(Mockito.any(User.class))).thenReturn(100);
Integer i = userService.insertUser(new User()); //會(huì)返回100

thenThrow 系列方法

當(dāng)調(diào)用 userService 的 getUserById() 時(shí)的參數(shù)是 9 時(shí),拋出一個(gè) RuntimeException

Mockito.when(userService.getUserById(9)).thenThrow(new RuntimeException("mock throw exception"));
User user = userService.getUserById(9); //會(huì)拋出一個(gè)RuntimeException

如果方法沒有返回值的話(即是方法定義為public void myMethod() {...}),要改用 doThrow() 拋出 Exception

Mockito.doThrow(new RuntimeException("mock throw exception")).when(userService).print();
userService.print(); //會(huì)拋出一個(gè)RuntimeException

verify 系列方法

檢查調(diào)用 userService 的 getUserById()、且參數(shù)為3的次數(shù)是否為1次

Mockito.verify(userService, Mockito.times(1)).getUserById(Mockito.eq(3)) ;

驗(yàn)證調(diào)用順序,驗(yàn)證 userService 是否先調(diào)用 getUserById() 兩次,并且第一次的參數(shù)是 3、第二次的參數(shù)是 5,然后才調(diào)用insertUser() 方法

InOrder inOrder = Mockito.inOrder(userService);
inOrder.verify(userService).getUserById(3);
inOrder.verify(userService).getUserById(5);
inOrder.verify(userService).insertUser(Mockito.any(User.class));

4. Mockito的限制

上述就是 Mockito 的 mock 對(duì)象使用方法,不過當(dāng)使用 Mockito 在 mock 對(duì)象時(shí),有一些限制需要遵守

  • 不能 mock 靜態(tài)方法
  • 不能 mock private 方法
  • 不能 mock final class

因此在寫代碼時(shí),需要做良好的功能拆分,才能夠使用 Mockito 的 mock 技術(shù),幫助我們降低測(cè)試時(shí) bean 的耦合度

5. 總結(jié)

Mockito 是一個(gè)非常強(qiáng)大的框架,可以在執(zhí)行單元測(cè)試時(shí)幫助我們模擬一個(gè) bean,提高單元測(cè)試的穩(wěn)定性

并且大家可以嘗試在寫代碼時(shí),從 mock 測(cè)試的角度來寫,更能夠?qū)懗龉δ芮蟹至己玫拇a架構(gòu),像是如果有把專門和外部服務(wù)溝通的代碼抽出來成一個(gè) bean,在進(jìn)行單元測(cè)試時(shí),只要透過 Mockito 更換掉那個(gè) bean 就行了

到此這篇關(guān)于SpringBoot單元測(cè)試框架Mockito介紹及使用的文章就介紹到這了,更多相關(guān)SpringBoot Mockito內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java獲取視頻時(shí)長及截取幀截圖詳解

    Java獲取視頻時(shí)長及截取幀截圖詳解

    這篇文章主要介紹了Java獲取視頻時(shí)長及截取幀截圖詳解,以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。,需要的朋友可以參考下
    2019-06-06
  • springboot @Valid注解對(duì)嵌套類型的校驗(yàn)功能

    springboot @Valid注解對(duì)嵌套類型的校驗(yàn)功能

    這篇文章主要介紹了springboot~@Valid注解對(duì)嵌套類型的校驗(yàn),主要介紹 @Valid在項(xiàng)目中的使用,需要的朋友可以參考下
    2018-05-05
  • java服務(wù)端微信APP支付接口詳解

    java服務(wù)端微信APP支付接口詳解

    這篇文章主要為大家詳細(xì)介紹了java服務(wù)端微信APP支付接口,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Java HashMap在遍歷時(shí)刪除元素的實(shí)現(xiàn)

    Java HashMap在遍歷時(shí)刪除元素的實(shí)現(xiàn)

    本文主要介紹了Java HashMap在遍歷時(shí)刪除元素的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-12-12
  • Java之SpringBoot實(shí)現(xiàn)基本增刪改查(前后端分離版)

    Java之SpringBoot實(shí)現(xiàn)基本增刪改查(前后端分離版)

    這篇文章主要介紹了Java中SpringBoot如何實(shí)現(xiàn)基本的增刪改查,前后端分離版,沒有和前端進(jìn)行聯(lián)系,感興趣的小伙伴可以借鑒閱讀本文
    2023-03-03
  • idea中創(chuàng)建jsp項(xiàng)目的詳細(xì)實(shí)戰(zhàn)步驟

    idea中創(chuàng)建jsp項(xiàng)目的詳細(xì)實(shí)戰(zhàn)步驟

    才學(xué)javaWeb,以防自己忘記創(chuàng)建項(xiàng)目的過程,所以淺淺的記錄一下吧,下面這篇文章主要給大家介紹了關(guān)于idea中創(chuàng)建jsp項(xiàng)目的詳細(xì)步驟,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • Java實(shí)現(xiàn)二叉搜索樹的插入、刪除功能

    Java實(shí)現(xiàn)二叉搜索樹的插入、刪除功能

    這篇文章主要介紹了Java實(shí)現(xiàn)二叉搜索樹的插入、刪除,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-01-01
  • 淺談Java 代理機(jī)制

    淺談Java 代理機(jī)制

    Java 有兩種代理方式,一種是靜態(tài)代理,另一種是動(dòng)態(tài)代理。如果我們?cè)诖a編譯時(shí)就確定了被代理的類是哪一個(gè),那么就可以直接使用靜態(tài)代理;如果不能確定,那么可以使用類的動(dòng)態(tài)加載機(jī)制,在代碼運(yùn)行期間加載被代理的類這就是動(dòng)態(tài)代理
    2021-06-06
  • jdk17?SpringBoot?JPA集成多數(shù)據(jù)庫的示例詳解

    jdk17?SpringBoot?JPA集成多數(shù)據(jù)庫的示例詳解

    這篇文章主要介紹了jdk17?SpringBoot?JPA集成多數(shù)據(jù)庫的示例代碼,包括配置類、請(qǐng)求攔截器、線程上下文等相關(guān)知識(shí),代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • Java中集合List、Set和Map的入門詳細(xì)介紹

    Java中集合List、Set和Map的入門詳細(xì)介紹

    Java集合主要分為三種類型:Set(集)、List(列表)和Map(映射),下面這篇文章主要給大家介紹了關(guān)于Java中集合List、Set和Map的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-01-01

最新評(píng)論

枣庄市| 民乐县| 慈溪市| 黑山县| 开江县| 海南省| 嘉峪关市| 当涂县| 广汉市| 巫山县| 屏边| 二手房| 内江市| 彭泽县| 紫云| 潜江市| 铁岭市| 甘谷县| 伽师县| 南召县| 仲巴县| 舒兰市| 泸水县| 大城县| 瑞金市| 涟源市| 蒲江县| 荆门市| 甘孜县| 涪陵区| 兴文县| 米易县| 四川省| 齐齐哈尔市| 太仆寺旗| 大方县| 金寨县| 吉林省| 镇雄县| 山阴县| 达孜县|