單元測試之Mockito

關(guān)鍵詞:Mockito

以下內(nèi)容翻譯整理自:
Mockito latest documentation
[譯] 使用強(qiáng)大的 Mockito 測試框架來測試你的代碼

Unit tests with Mockito - Tutorial
When/how to use Mockito Answer(需要翻墻)
使用Mockito對(duì)異步方法進(jìn)行單元測試

2. 使用mock對(duì)象進(jìn)行測試

單元測試應(yīng)該盡可能隔離其他類或系統(tǒng)的影響占贫。

  • dummy object
  • Fake objects
  • stub class
  • mock object

可以使用mock框架創(chuàng)建mock對(duì)象來模擬類巴刻,mock框架允許在運(yùn)行時(shí)創(chuàng)建mock對(duì)象,并定義它們的行為畴栖。
Mockito是目前流行的mock框架投队,可以配合JUnit使用寝志。Mockito支持創(chuàng)建和設(shè)置mock對(duì)象。使用Mockito可以顯著的簡化對(duì)那些有外部依賴的類的測試缸剪。

  • mock測試代碼中的外部依賴
  • 執(zhí)行測試
  • 驗(yàn)證代碼是否執(zhí)行正確
mockito

4. 使用Mockito API

  • Static imports
    添加static import org.mockito.Mockito.*;

  • Creating and configuring mock objects with Mockito

Mockito支持通過靜態(tài)方法mock()創(chuàng)建mock對(duì)象吗铐,也可以使用@Mock注解。如果使用注解的方式杏节,必須初始化mock對(duì)象唬渗。使用MockitoRule典阵,調(diào)用靜態(tài)方法MockitoAnnotations.initMocks(this)初始化標(biāo)示的屬性字段。

import static org.mockito.Mockito.*;

public class MockitoTest {
    @Mock
    MyDatabase databaseMock;
  
    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();
 
    @Test
    public void testQuery() {
        ClassToTest t = new ClassToTest(databaseMock);
        boolean check = t.query("* from t"); 
        assertTrue(check);
        verify(databaseMock).query("* from t"); 
    }
}
  • Configuring mocks

    • when(…?.).thenReturn(…?.)用于指定條件滿足時(shí)的返回值镊逝,也可以根據(jù)不同的傳入?yún)?shù)返回不同的值壮啊。
    • doReturn(…?).when(…?).methodCall作用類似,但是用于返回值為void的函數(shù)撑蒜。
  • Verify the calls on the mock objects
    Mockito會(huì)跟蹤mock對(duì)象所有的函數(shù)調(diào)用以及它們的參數(shù)歹啼,可以用verify()驗(yàn)證
    一個(gè)函數(shù)有沒有被調(diào)用with指定的參數(shù)。這個(gè)被稱為"behavior testing"

  • Wrapping Java objects with Spy
    @Spyspy()方法用于封裝實(shí)際的對(duì)象座菠。除非有特殊聲明(stub)狸眼,都會(huì)真正的調(diào)用對(duì)象的方法。

  • Using @InjectMocks for dependency injection via Mockito

    • You also have the @InjectMocks annotation which tries to do constructor, method or field dependency injection based on the type.
  • Capturing the arguments
    ArgumentCaptor允許我們在verification期間訪問函數(shù)的參數(shù)辈灼。在捕獲這些函數(shù)參數(shù)后份企,可以用于測試。

  • Limitations
    以下不能使用Mockito測試
    • final classes
    • anonymous classes
    • primitive types
1. Mockito Answer的使用

A common usage of Answer is to stub asynchronous methods that have callbacks.

doAnswer(new Answer<Void>() {
    public Void answer(InvocationOnMock invocation) {
    Callback callback = (Callback) invocation.getArguments()[0];
    callback.onSuccess(cannedData);
    return null;
    }
}).when(service).get(any(Callback.class));

Answer can also be used to make smarter stubs for synchronous methods.

when(translator.translate(any(String.class))).thenAnswer(reverseMsg())
...
// extracted a method to put a descriptive name
private static Answer<String> reverseMsg() {
    return new Answer<String>() {
        public String answer(InvocationOnMock invocation) {
            return reverseString((String) invocation.getArguments()[0]));
        }
    }
}

Mockito限制

  • final classes
  • anonymous classes
  • primitive types

Mockito示例

1. Let's verify some behaviour!
//Let's import Mockito statically so that the code looks clearer 
import static org.mockito.Mockito.*; 

//mock creation 
List mockedList = mock(List.class); 

//using mock object 
mockedList.add("one"); 
mockedList.clear(); 

//verification 
verify(mockedList).add("one"); 
verify(mockedList).clear();

驗(yàn)證某些操作是否執(zhí)行

Once created, a mock will remember all interactions. Then you can selectively verify whatever interactions you are interested in.

2. How about some stubbing?
//You can mock concrete classes, not just interfaces 
LinkedList mockedList = mock(LinkedList.class); 

//stubbing 
when(mockedList.get(0)).thenReturn("first"); 
when(mockedList.get(1)).thenThrow(new RuntimeException()); 

//following prints "first" 
System.out.println(mockedList.get(0)); 
//following throws runtime exception 
System.out.println(mockedList.get(1)); 
//following prints "null" because get(999) was not stubbed 
System.out.println(mockedList.get(999)); 

//Although it is possible to verify a stubbed invocation, usually **it's just redundant** 
//If your code cares what get(0) returns, then something else breaks (often even before verify() gets executed). 
//If your code doesn't care what get(0) returns, then it should not be stubbed. Not convinced? See [here](http://monkeyisland.pl/2008/04/26/asking-and-telling). 
verify(mockedList).get(0);

By default, for all methods that return a value, a mock will return either null, a a primitive/primitive wrapper value, or an empty collection, as appropriate. For example 0 for an int/Integer and false for a boolean/Boolean.

3. Argument matchers
//stubbing using built-in anyInt() argument matcher 
when(mockedList.get(anyInt())).thenReturn("element"); 

//stubbing using custom matcher (let's say isValid() returns your own matcher implementation): 
when(mockedList.contains(argThat(isValid()))).thenReturn("element"); 

//following prints "element" 
System.out.println(mockedList.get(999)); 

//**you can also verify using an argument matcher** 
verify(mockedList).get(anyInt()); 

//**argument matchers can also be written as Java 8 Lambdas** 
verify(mockedList).add(someString -> someString.length() > 5);

If you are using argument matchers, all arguments have to be provided by matchers.

5. Stubbing void methods with exceptions
doThrow(new RuntimeException()).when(mockedList).clear(); 

//following throws RuntimeException: 
mockedList.clear();
6. Verification in order
// A. Single mock whose methods must be invoked in a particular order 
List singleMock = mock(List.class); 

//using a single mock 
singleMock.add("was added first"); 
singleMock.add("was added second"); 

//create an inOrder verifier for a single mock 
InOrder inOrder = inOrder(singleMock); 

//following will make sure that add is first called with "was added first, then with "was added second" 
inOrder.verify(singleMock).add("was added first"); 
inOrder.verify(singleMock).add("was added second"); 

// B. Multiple mocks that must be used in a particular order 
List firstMock = mock(List.class); 
List secondMock = mock(List.class); 

//using mocks 
firstMock.add("was called first"); 
secondMock.add("was called second"); 

//create inOrder object passing any mocks that need to be verified in order 
InOrder inOrder = inOrder(firstMock, secondMock); 

//following will make sure that firstMock was called before secondMock 
inOrder.verify(firstMock).add("was called first"); 
inOrder.verify(secondMock).add("was called second"); 

// Oh, and A + B can be mixed together at will
7. Making sure interaction(s) never happened on mock
//using mocks - only mockOne is interacted 
mockOne.add("one"); 

//ordinary verification 
verify(mockOne).add("one"); 

//verify that method was never called on a mock 
verify(mockOne, never()).add("two"); 

//verify that other mocks were not interacted 
verifyZeroInteractions(mockTwo, mockThree);
8. Finding redundant invocations
//using mocks 
mockedList.add("one"); 
mockedList.add("two"); 

verify(mockedList).add("one"); 

//following verification will fail 
verifyNoMoreInteractions(mockedList);

verifyNoMoreInteractions() is a handy assertion from the interaction testing toolkit. Use it only when it's relevant. Abusing it leads to overspecified, less maintainable tests.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末巡莹,一起剝皮案震驚了整個(gè)濱河市司志,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌降宅,老刑警劉巖骂远,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異腰根,居然都是意外死亡激才,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門额嘿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瘸恼,“玉大人,你說我怎么就攤上這事册养《В” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵球拦,是天一觀的道長靠闭。 經(jīng)常有香客問我,道長坎炼,這世上最難降的妖魔是什么愧膀? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮谣光,結(jié)果婚禮上檩淋,老公的妹妹穿的比我還像新娘。我一直安慰自己萄金,他們只是感情好狼钮,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布碳柱。 她就那樣靜靜地躺著,像睡著了一般熬芜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上福稳,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天涎拉,我揣著相機(jī)與錄音,去河邊找鬼的圆。 笑死鼓拧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的越妈。 我是一名探鬼主播季俩,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼梅掠!你這毒婦竟也來了酌住?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤阎抒,失蹤者是張志新(化名)和其女友劉穎酪我,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體且叁,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡都哭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逞带。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欺矫。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖展氓,靈堂內(nèi)的尸體忽然破棺而出穆趴,到底是詐尸還是另有隱情,我是刑警寧澤带饱,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布毡代,位于F島的核電站,受9級(jí)特大地震影響勺疼,放射性物質(zhì)發(fā)生泄漏教寂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一执庐、第九天 我趴在偏房一處隱蔽的房頂上張望酪耕。 院中可真熱鬧,春花似錦轨淌、人聲如沸迂烁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盟步。三九已至藏斩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間却盘,已是汗流浹背狰域。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留黄橘,地道東北人兆览。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像塞关,于是被迫代替她去往敵國和親抬探。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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

  • 在博客Android單元測試之JUnit4中帆赢,我們簡單地介紹了:什么是單元測試小压,為什么要用單元測試,并展示了一個(gè)簡...
    水木飛雪閱讀 9,394評(píng)論 4 18
  • 背景 在寫單元測試的過程中匿醒,一個(gè)很普遍的問題是场航,要測試的目標(biāo)類會(huì)有很多依賴,這些依賴的類/對(duì)象/資源又會(huì)有別的依賴...
    johnnycmj閱讀 1,154評(píng)論 0 3
  • 什么是Mock廉羔? 在單元測試中溉痢,我們往往想去獨(dú)立地去測一個(gè)類中的某個(gè)方法,但是這個(gè)類可不是獨(dú)立的憋他,它會(huì)去調(diào)用一些其...
    健談的Boris閱讀 22,697評(píng)論 0 14
  • 什么是 Mock mock 的中文譯為: 仿制的孩饼,模擬的,虛假的竹挡。對(duì)于測試框架來說镀娶,即構(gòu)造出一個(gè)模擬/虛假的對(duì)象,...
    Whyn閱讀 4,334評(píng)論 0 3
  • 寫在前面 因個(gè)人能力有限揪罕,可能會(huì)出現(xiàn)理解錯(cuò)誤的地方梯码,歡迎指正和交流! 關(guān)于單元測試 通常一個(gè)優(yōu)秀的開源框架好啰,一般都...
    汪海游龍閱讀 2,885評(píng)論 0 21