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

SpringBoot單元測試框架Mockito介紹及使用

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

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

1. 什么是mock測試

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

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

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

2. Mockito簡介

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

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

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

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

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

3. 在SpringBoot單元測試中使用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>

先寫好一個 UserService,他里面有兩個方法getUserById()insertUser(),而他們會分別去再去調(diào)用 UserDao 這個 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
}

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

@RunWith(SpringRunner.class)
@SpringBootTest
publicclass UserServiceTest {
    //先普通的注入一個userService bean
    @Autowired
    private UserService userService;
    @Test
    public void getUserById() throws Exception {
        //普通的使用userService,他里面會再去調(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 還沒寫好,又想先測 userService 的話,就需要使用 Mockito 去模擬一個假的 userDao 出來

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

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

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

使用 Mockito 模擬 bean 的單元測試具體實例如下

@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時,就返回id為200、name為I'm mock3的user對象
        Mockito.when(userDao.getUserById(3)).thenReturn(new User(200, "I'm mock 3"));
        // 返回的會是名字為I'm mock 3的user對象
        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( 對象.方法名() ).thenReturn( 自定義結(jié)果 ),還提供了其他用法讓我們使用

thenReturn 系列方法

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

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 時,才會回傳名字為 I'm mock 3 的 user 對象

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() 方法時,不管傳進(jìn)來的 user 是什麼,都回傳 100

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

thenThrow 系列方法

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

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

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

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

verify 系列方法

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

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

驗證調(diào)用順序,驗證 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 對象使用方法,不過當(dāng)使用 Mockito 在 mock 對象時,有一些限制需要遵守

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

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

5. 總結(jié)

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

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

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

相關(guān)文章

  • 詳細(xì)解讀AbstractStringBuilder類源碼

    詳細(xì)解讀AbstractStringBuilder類源碼

    這篇文章主要介紹了詳細(xì)解讀AbstractStringBuilder類源碼,具有一定參考價值,需要的朋友可以了解下。
    2017-12-12
  • Java 回調(diào)機(jī)制(CallBack) 詳解及實例代碼

    Java 回調(diào)機(jī)制(CallBack) 詳解及實例代碼

    這篇文章主要介紹了 Java 回調(diào)機(jī)制(CallBack) 詳解及實例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • SpringBoot中@Import注解的使用方式

    SpringBoot中@Import注解的使用方式

    這篇文章主要介紹了SpringBoot中@Import注解的使用方式,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-05-05
  • MyBatis執(zhí)行動態(tài)SQL的方法

    MyBatis執(zhí)行動態(tài)SQL的方法

    今天小編就為大家分享一篇關(guān)于MyBatis執(zhí)行動態(tài)SQL的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • java后臺判斷客戶端是手機(jī)/PC并返回不同頁面的實例

    java后臺判斷客戶端是手機(jī)/PC并返回不同頁面的實例

    下面小編就為大家分享一篇java后臺判斷客戶端是手機(jī)/PC并返回不同頁面的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • 詳解@Autowired是如何注入變量的

    詳解@Autowired是如何注入變量的

    在?Spring?容器中,當(dāng)我們想給某一個屬性注入值的時候,有多種不同的方式,例如使用?@Autowired、@Inject等注解,下面小編就來和小伙伴們聊一聊,@Autowired?到底是如何把數(shù)據(jù)注入進(jìn)來的
    2023-07-07
  • MySQL安裝與idea的連接實現(xiàn)

    MySQL安裝與idea的連接實現(xiàn)

    本文主要介紹了MySQL安裝與idea的連接實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Java異常處理學(xué)習(xí)心得

    Java異常處理學(xué)習(xí)心得

    本篇文章給大家詳細(xì)講述了學(xué)習(xí)Java異常處理學(xué)習(xí)的心得以及原理介紹,對此有興趣的朋友參考下吧。
    2018-01-01
  • SpringBoot 注解事務(wù)聲明式事務(wù)的方式

    SpringBoot 注解事務(wù)聲明式事務(wù)的方式

    springboot使用上述注解的幾種方式開啟事物,可以達(dá)到和xml中聲明的同樣效果,但是卻告別了xml,使你的代碼遠(yuǎn)離配置文件。今天就扒一扒springboot中事務(wù)使用注解的玩法,感興趣的朋友一起看看吧
    2017-09-09
  • java中的日期時間類Date和SimpleDateFormat

    java中的日期時間類Date和SimpleDateFormat

    這篇文章主要介紹了java中的日期時間類Date和SimpleDateFormat,Date類的對象在Java中代表的是當(dāng)前所在系統(tǒng)的此刻日期時間,說白了就是你計算機(jī)上現(xiàn)實的時間,需要的朋友可以參考下
    2023-09-09

最新評論