在SpringBoot中編寫Mock單元測試

1. 新建測試類

在IDEA中寫好的類中,右建GO TO,選擇TEST,如果沒有對應(yīng)的單元測試類就選擇創(chuàng)建涯雅。

在創(chuàng)建該類的單元測試類前,先講一下這幾個基本注解:

@Test:使用該注解標(biāo)注的public void方法會表示為一個測試方法展运;
@BeforeClass:表示在類中的任意public static void方法執(zhí)行之前執(zhí)行活逆;
@AfterClass:表示在類中的任意public static void方法之后執(zhí)行;
@Before:表示在任意使用@Test注解標(biāo)注的public void方法執(zhí)行之前執(zhí)行拗胜;
@After:表示在任意使用@Test注解標(biāo)注的public void方法執(zhí)行之后執(zhí)行蔗候;

2. 添加依賴

新建的springBoot項目中默認包含了spring-boot-starter-test的依賴,如果沒有包含可自行在pom.xml中添加依賴埂软。

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

3. Mock的概念

所謂的mock就是創(chuàng)建一個類的虛假的對象锈遥,在測試環(huán)境中,用來替換掉真實的對象勘畔,以達到兩大目的:

  1. 驗證這個對象的某些方法的調(diào)用情況所灸,調(diào)用了多少次,參數(shù)是什么等等
  2. 指定這個對象的某些方法的行為炫七,返回特定的值爬立,或者是執(zhí)行特定的動作

使用Mock之前,需要在@Before或@BeforeClass對應(yīng)的方法中添加如下万哪,表示添加mock注解初始化侠驯。

MockitoAnnotations.initMocks(this);

另外需要補充以下幾個常用的測試注解:

  • @InjectMocks:通過創(chuàng)建一個實例,它可以調(diào)用真實代碼的方法奕巍,其余用@Mock(或@Spy)注解創(chuàng)建的mock將被注入到用該實例中吟策。

  • @Mock:對函數(shù)的調(diào)用均執(zhí)行mock(即虛假函數(shù)),不執(zhí)行真正部分的止。

  • @Spy:對函數(shù)的調(diào)用均執(zhí)行真正部分檩坚。

Mockito中的Mock和Spy都可用于攔截那些尚未實現(xiàn)或不期望被真實調(diào)用的對象和方法,并為其設(shè)置自定義行為诅福。二者的區(qū)別在于Mock不真實調(diào)用匾委,Spy會真實調(diào)用。

  • @mock與@spy使用示例

(1)被測試類

class ExampleService {
  
    int add(int a, int b) {
        return a+b;
    }
  
}

(2)測試類

import org.junit.Assert;
import org.junit.Test;
import static org.mockito.Mockito.*;

public class MockitoDemo {
    @Spy
    private ExampleService spyExampleService;
  
    @Mock
    private ExampleService mockExampleService;

    // 測試 spy
    @Test
    public void test_spy() {
      
        // 默認會走真實方法
        Assert.assertEquals(3, spyExampleService.add(1, 2));

        // 打樁后权谁,不會走了
        when(spyExampleService.add(1, 2)).thenReturn(10);
        Assert.assertEquals(10, spyExampleService.add(1, 2));

        // 但是參數(shù)不匹配的調(diào)用剩檀,依然走真實方法
        Assert.assertEquals(3, spyExampleService.add(2, 1));
      
    }

    // 測試 mock
    @Test
    public void test_mock() {

        // 默認返回結(jié)果是返回類型int的默認值
        Assert.assertEquals(0, mockExampleService.add(1, 2));

    }
}
  • @InjectMock和@Mock使用示例

(1)被測試類

class MockExampleService {
    
    int add(int a, int b) {
        return a+b;
    }
  
}

class InjectMockExampleService {
    
    @Autowired
    private MockExampleService mockExampleService;
      
    int add(int a, int b) {
        return mockExampleService.add(a, b);
    }
  
}

(2)測試類

import org.junit.Assert;
import org.junit.Test;
import static org.mockito.Mockito.*;

public class MockitoDemo {
    @InjectMock
    private InjectMockExampleService injectMockExampleService;
  
    @Mock
    private MockExampleService mockExampleService;
    
    // 初始化漢順
    @Before
    public void init() throw Exception {
            MockitoAnnotations.initMocks(this);
    }

    // 使用Mockito模擬
    @Test
    public void test() {
      
        // 模擬MockExampleServiceadd函數(shù)對于任何參數(shù)返回都為10
                when(mockExampleService.add(anyInt(), anyInt())).thenReturn(10);
        // InjectMock會走真實的add方法,只不過mock會返回一個模擬的結(jié)果
        Assert.assertEquals(10, injectMockExampleService.add(1, 2));

    }
}

4. 常用的 Mockito 方法

Mockito的使用旺芽,一般有以下幾種組合:參考鏈接

  • do/when:包括doThrow(…).when(…)/doReturn(…).when(…)/doAnswer(…).when(…)
  • given/will:包括given(…).willReturn(…)/given(…).willAnswer(…)
  • when/then: 包括when(…).thenReturn(…)/when(…).thenAnswer(…)/when(…).thenThrow(…)

Mockito 有多種匹配函數(shù),部分如下:

函數(shù)名 匹配類型
any() 所有對象類型
anyInt() 基本類型 int、非 null 的 Integer 類型
anyChar() 基本類型 char采章、非 null 的 Character 類型
anyShort() 基本類型 short运嗜、非 null 的 Short 類型
anyBoolean() 基本類型 boolean、非 null 的 Boolean 類型
anyDouble() 基本類型 double悯舟、非 null 的 Double 類型
anyFloat() 基本類型 float担租、非 null 的 Float 類型
anyLong() 基本類型 long、非 null 的 Long 類型
anyByte() 基本類型 byte抵怎、非 null 的 Byte 類型
anyString() String 類型(不能是 null)
anyList() List<T> 類型(不能是 null)
anyMap() Map<K, V>類型(不能是 null)

5. 參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奋救,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子反惕,更是在濱河造成了極大的恐慌尝艘,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姿染,死亡現(xiàn)場離奇詭異背亥,居然都是意外死亡,警方通過查閱死者的電腦和手機悬赏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門狡汉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人闽颇,你說我怎么就攤上這事盾戴。” “怎么了兵多?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵捻脖,是天一觀的道長。 經(jīng)常有香客問我中鼠,道長可婶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任援雇,我火速辦了婚禮矛渴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惫搏。我一直安慰自己具温,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布筐赔。 她就那樣靜靜地躺著铣猩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪茴丰。 梳的紋絲不亂的頭發(fā)上达皿,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天天吓,我揣著相機與錄音,去河邊找鬼峦椰。 笑死龄寞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的汤功。 我是一名探鬼主播物邑,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼滔金!你這毒婦竟也來了色解?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤餐茵,失蹤者是張志新(化名)和其女友劉穎科阎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钟病,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡萧恕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了肠阱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片票唆。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖屹徘,靈堂內(nèi)的尸體忽然破棺而出走趋,到底是詐尸還是另有隱情,我是刑警寧澤噪伊,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布簿煌,位于F島的核電站,受9級特大地震影響鉴吹,放射性物質(zhì)發(fā)生泄漏姨伟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一豆励、第九天 我趴在偏房一處隱蔽的房頂上張望夺荒。 院中可真熱鬧,春花似錦良蒸、人聲如沸技扼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剿吻。三九已至,卻和暖如春串纺,著一層夾襖步出監(jiān)牢的瞬間丽旅,已是汗流浹背椰棘。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留魔招,地道東北人晰搀。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓五辽,卻偏偏與公主長得像办斑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子杆逗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容