Mockito中文文檔

轉自:https://github.com/hehonghui/mockito-doc-zh

文章目錄

Mockito 中文文檔 ( 2.0.26 beta )

由於缺乏校對,難免有謬誤之處,如果發現任何語句不通順、翻譯錯誤,都可以在github中的項目提出issue。謝謝~

Mockito框架官方地址mockito文檔地址

Mockito庫能夠Mock對象、驗證結果以及打樁(stubbing)。

該文檔您也可以通過http://mockito.org獲取到。所有文檔都保存在javadocs中,因爲它能夠保證文檔與源代碼的一致性。這樣也能夠讓離線的用戶從IDE直接訪問到文檔。這樣一來也能夠激勵Mockito開發者在每次寫代碼、每次提交時更新對應的文檔。

參與人員

成員 任務
Mr.Simple 1-15
chaosss 16-26
tiiime 27~35
dengshiwei a~c開頭的方法,包含
objectlife d~m開頭的方法
Conquer n-w開頭的函數

目錄

  1. 遷移到Mockito 2.0
  2. 驗證某些行爲
  3. 如何做一些測試樁 (Stub)
  4. 參數匹配器 (matchers)
  5. 驗證函數的確切、最少、從未調用次數
  6. 爲返回值爲void的函數通過Stub拋出異常
  7. 按照順序驗證執行結果
  8. 確保交互(interaction)操作不會執行在mock對象上
  9. 查找冗餘的調用
  10. 簡化mock對象的創建
  11. 爲連續的調用做測試樁 (stub)
  12. 爲回調做測試樁
  13. doReturn()、doThrow()、doAnswer()、doNothing()、doCallRealMethod()系列方法的運用
  14. 監控真實對象
  15. 修改沒有測試樁的調用的默認返回值 ( 1.7版本之後 )
  16. 爲下一步的斷言捕獲參數 (1.8版本之後)
  17. 真實的局部mocks (1.8版本之後)
  18. 重置mocks對象 (1.8版本之後)
  19. 故障排查與驗證框架的使用 (1.8版本之後)
  20. 行爲驅動開發的別名 (1.8版本之後)
  21. 序列化mock對象
  22. 新的註解 : @Captor,@Spy,@ InjectMocks (1.8.3版本之後)
  23. 驗證超時 (1.8.5版本之後)
  24. 自動初始化被@Spies, @InjectMocks註解的字段以及構造函數注入 (1.9.0版本之後)
  25. 單行測試樁 (1.9.0版本之後)
  26. 驗證被忽略的測試樁 (1.9.0版本之後)
  27. mock詳情 (1.9.5版本之後)
  28. delegate調用真實的實例 (1.9.5版本之後)
  29. MockMaker API (1.9.5版本之後)
  30. BDD風格的驗證 (1.10.0版本之後)
  31. 追蹤或者Mock抽象類 (1.10.12版本之後)
  32. Mockito mock對象通過ClassLoader能被序列化/反序列化 (1.10.0版本之後)
  33. deep stubs更好的支持泛型 (1.10.0版本之後)
  34. Mockito JUnit 規則 (1.10.17版本之後)
  35. 開/關插件 (1.10.15版本之後)
  36. 自定義驗證失敗消息 (2.0.0版本之後)

0. 遷移到Mockito 2.0

爲了持續提升Mockito以及更進一步的提升單元測試體驗,我們希望你升級到Mockito 2.0.Mockito遵循語意化的版本控制,除非有非常大的改變纔會變化主版本號。在一個庫的生命週期中,爲了引入一系列有用的特性,修改已存在的行爲或者API等重大變更是在所難免的。因此,我們希望你能夠愛上 Mockito 2.0!

重要變更 :

  • Mockito從Hamcrest中解耦,自定義的matchers API也發生了改變,查看ArgumentMatcher 的基本原理以及遷移指南。

跟着我們的示例來mock 一個List,因爲大家都知道它的接口(例如add(),get(), clear())。不要mock一個真實的List類型,使用一個真實的實例來替代。

1. 驗證某些行爲

 // 靜態導入會使代碼更簡潔
 import static org.mockito.Mockito.*;

 // mock creation 創建mock對象
 List mockedList = mock(List.class);

 //using mock object 使用mock對象
 mockedList.add("one");
 mockedList.clear();

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

一旦mock對象被創建了,mock對象會記住所有的交互。然後你就可能選擇性的驗證你感興趣的交互。

2. 如何做一些測試樁 (Stub)

 //You can mock concrete classes, not only interfaces
 // 你可以mock具體的類型,不僅只是接口
 LinkedList mockedList = mock(LinkedList.class);

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

 //following prints "first"
 // 輸出“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
 // 因爲get(999) 沒有打樁,因此輸出null
 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 before even verify() gets executed).
 //If your code doesn't care what get(0) returns then it should not be stubbed. Not convinced? See here.
 // 驗證get(0)被調用的次數
 verify(mockedList).get(0);
  • 默認情況下,所有的函數都有返回值。mock函數默認返回的是null,一個空的集合或者一個被對象類型包裝的內置類型,例如0、false對應的對象類型爲Integer、Boolean;
  • 測試樁函數可以被覆寫 : 例如常見的測試樁函數可以用於初始化夾具,但是測試函數能夠覆寫它。請注意,覆寫測試樁函數是一種可能存在潛在問題的做法;
  • 一旦測試樁函數被調用,該函數將會一致返回固定的值;
  • 上一次調用測試樁函數有時候極爲重要-當你調用一個函數很多次時,最後一次調用可能是你所感興趣的。

3. 參數匹配器 (matchers)

Mockito以自然的java風格來驗證參數值: 使用equals()函數。有時,當需要額外的靈活性時你可能需要使用參數匹配器,也就是argument matchers :

 //stubbing using built-in anyInt() argument matcher
 // 使用內置的anyInt()參數匹配器
 when(mockedList.get(anyInt())).thenReturn("element");

 //stubbing using custom matcher (let's say isValid() returns your own matcher implementation):
 // 使用自定義的參數匹配器( 在isValid()函數中返回你自己的匹配器實現 )
 when(mockedList.contains(argThat(isValid()))).thenReturn("element");

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

 //you can also verify using an argument matcher
 // 你也可以驗證參數匹配器
 verify(mockedList).get(anyInt());

參數匹配器使驗證和測試樁變得更靈活。點擊這裏查看更多內置的匹配器以及自定義參數匹配器或者hamcrest 匹配器的示例。

如果僅僅是獲取自定義參數匹配器的信息,查看ArgumentMatcher類文檔即可。

爲了合理的使用複雜的參數匹配,使用equals()與anyX() 的匹配器會使得測試代碼更簡潔、簡單。有時,會迫使你重構代碼以使用equals()匹配或者實現equals()函數來幫助你進行測試。

同時建議你閱讀第15章節或者ArgumentCaptor類文檔。ArgumentCaptor是一個能夠捕獲參數值的特俗參數匹配器。

參數匹配器的注意點 :

如果你使用參數匹配器,所有參數都必須由匹配器提供。

示例 : ( 該示例展示瞭如何多次應用於測試樁函數的驗證 )

verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
//above is correct - eq() is also an argument matcher
// 上述代碼是正確的,因爲eq()也是一個參數匹配器

verify(mock).someMethod(anyInt(), anyString(), "third argument");
//above is incorrect - exception will be thrown because third argument 
// 上述代碼是錯誤的,因爲所有參數必須由匹配器提供,而參數"third argument"並非由參數匹配器提供,因此的緣故會拋出異常

像anyObject(), eq()這樣的匹配器函數不會返回匹配器。它們會在內部將匹配器記錄到一個棧當中,並且返回一個假的值,通常爲null。這樣的實現是由於被Java編譯器強加的靜態類型安全。結果就是你不能在驗證或者測試樁函數之外使用anyObject(), eq()函數。

4. 驗證函數的確切、最少、從未調用次數

 //using mock
 mockedList.add("once");

 mockedList.add("twice");
 mockedList.add("twice");

 mockedList.add("three times");
 mockedList.add("three times");
 mockedList.add("three times");

 //following two verifications work exactly the same - times(1) is used by default
 // 下面的兩個驗證函數效果一樣,因爲verify默認驗證的就是times(1)
 verify(mockedList).add("once");
 verify(mockedList, times(1)).add("once");

 //exact number of invocations verification
 // 驗證具體的執行次數
 verify(mockedList, times(2)).add("twice");
 verify(mockedList, times(3)).add("three times");

 //verification using never(). never() is an alias to times(0)
 // 使用never()進行驗證,never相當於times(0)
 verify(mockedList, never()).add("never happened");

 //verification using atLeast()/atMost()
 // 使用atLeast()/atMost()
 verify(mockedList, atLeastOnce()).add("three times");
 verify(mockedList, atLeast(2)).add("five times");
 verify(mockedList, atMost(5)).add("three times");

verify函數默認驗證的是執行了times(1),也就是某個測試函數是否執行了1次.因此,times(1)通常被省略了。

5. 爲返回值爲void的函數通過Stub拋出異常

doThrow(new RuntimeException()).when(mockedList).clear();

//following throws RuntimeException:
// 調用這句代碼會拋出異常
mockedList.clear();

關於doThrow|doAnswer 等函數族的信息請閱讀第十二章節。

最初,stubVoid(Object) 函數用於爲無返回值的函數打樁。現在stubVoid()函數已經過時,doThrow(Throwable)成爲了它的繼承者。這是爲了提升與 doAnswer(Answer) 函數族的可讀性與一致性。

6. 驗證執行執行順序

 // A. Single mock whose methods must be invoked in a particular order
 // A. 驗證mock一個對象的函數執行順序
 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
 // 爲該mock對象創建一個inOrder對象
 InOrder inOrder = inOrder(singleMock);

 //following will make sure that add is first called with "was added first, then with "was added second"
 // 確保add函數首先執行的是add("was added first"),然後纔是add("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
 // B .驗證多個mock對象的函數執行順序
 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
 // 爲這兩個Mock對象創建inOrder對象
 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

驗證執行順序是非常靈活的-你不需要一個一個的驗證所有交互,只需要驗證你感興趣的對象即可。
另外,你可以僅通過那些需要驗證順序的mock對象來創建InOrder對象。

7. 確保交互(interaction)操作不會執行在mock對象上

 //using mocks - only mockOne is interacted
 // 使用Mock對象
 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
 // 驗證mock對象沒有交互過
 verifyZeroInteractions(mockTwo, mockThree);

8. 查找冗餘的調用

//using mocks
mockedList.add("one");
mockedList.add("two");

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

//following verification will fail
// 下面的驗證將會失敗
verifyNoMoreInteractions(mockedList);

一些用戶可能會在頻繁地使用verifyNoMoreInteractions(),甚至在每個測試函數中都用。但是verifyNoMoreInteractions()並不建議在每個測試函數中都使用。verifyNoMoreInteractions()在交互測試套件中只是一個便利的驗證,它的作用是當你需要驗證是否存在冗餘調用時。濫用它將導致測試代碼的可維護性降低。你可以閱讀這篇文檔來了解更多相關信息。

never()是一種更爲明顯且易於理解的形式。

9. 簡化mock對象的創建

  • 最小化重複的創建代碼
  • 使測試類的代碼可讀性更高
  • 使驗證錯誤更易於閱讀,因爲字段名可用於標識mock對象
public class ArticleManagerTest {

   @Mock private ArticleCalculator calculator;
   @Mock private ArticleDatabase database;
   @Mock private UserProvider userProvider;

   private ArticleManager manager;

注意!下面這句代碼需要在運行測試函數之前被調用,一般放到測試類的基類或者test runner中:

 MockitoAnnotations.initMocks(testClass);

你可以使用內置的runner: MockitoJUnitRunner runner 或者一個rule : MockitoRule
關於mock註解的更多信息可以閱讀MockitoAnnotations文檔

10. 爲連續的調用做測試樁 (stub)

有時我們需要爲同一個函數調用的不同的返回值或異常做測試樁。典型的運用就是使用mock迭代器。
原始版本的Mockito並沒有這個特性,例如,可以使用Iterable或者簡單的集合來替換迭代器。這些方法提供了更自然的方式,在一些場景中爲連續的調用做測試樁會很有用。示例如下 :

 when(mock.someMethod("some arg"))
   .thenThrow(new RuntimeException())
   .thenReturn("foo");

 //First call: throws runtime exception:
 // 第一次調用 : 拋出運行時異常
 mock.someMethod("some arg");

 //Second call: prints "foo"
 // 第二次調用 : 輸出"foo"
 System.out.println(mock.someMethod("some arg"));

 //Any consecutive call: prints "foo" as well (last stubbing wins).
 // 後續調用 : 也是輸出"foo"
 System.out.println(mock.someMethod("some arg"));

另外,連續調用的另一種更簡短的版本 :

// 第一次調用時返回"one",第二次返回"two",第三次返回"three"
 when(mock.someMethod("some arg"))
   .thenReturn("one", "two", "three");

11. 爲回調做測試樁

Allows stubbing with generic Answer interface.
運行爲泛型接口Answer打樁。

在最初的Mockito裏也沒有這個具有爭議性的特性。我們建議使用thenReturn() 或thenThrow()來打樁。這兩種方法足夠用於測試或者測試驅動開發。

 when(mock.someMethod(anyString())).thenAnswer(new Answer() {
     Object answer(InvocationOnMock invocation) {
         Object[] args = invocation.getArguments();
         Object mock = invocation.getMock();
         return "called with arguments: " + args;
     }
 });

 //Following prints "called with arguments: foo"
 // 輸出 : "called with arguments: foo"
 System.out.println(mock.someMethod("foo"));

12. doReturn()、doThrow()、doAnswer()、doNothing()、doCallRealMethod()系列方法的運用

通過when(Object)爲無返回值的函數打樁有不同的方法,因爲編譯器不喜歡void函數在括號內…

使用doThrow(Throwable) 替換stubVoid(Object)來爲void函數打樁是爲了與doAnswer()等函數族保持一致性。

當你想爲void函數打樁時使用含有一個exception 參數的doAnswer() :

doThrow(new RuntimeException()).when(mockedList).clear();

//following throws RuntimeException:
// 下面的代碼會拋出異常
mockedList.clear();

當你調用doThrow(), doAnswer(), doNothing(), doReturn() and doCallRealMethod() 這些函數時可以在適當的位置調用when()函數. 當你需要下面這些功能時這是必須的:

  • 測試void函數
  • 在受監控的對象上測試函數
  • 不知一次的測試爲同一個函數,在測試過程中改變mock對象的行爲。

但是在調用when()函數時你可以選擇是否調用這些上述這些函數。

閱讀更多關於這些方法的信息:

13. 監控真實對象

你可以爲真實對象創建一個監控(spy)對象。當你使用這個spy對象時真實的對象也會也調用,除非它的函數被stub了。儘量少使用spy對象,使用時也需要小心形式,例如spy對象可以用來處理遺留代碼。

監控一個真實的對象可以與“局部mock對象”概念結合起來。在1.8之前,mockito的監控功能並不是真正的局部mock對象。原因是我們認爲局部mock對象的實現方式並不好,在某些時候我發現一些使用局部mock對象的合法用例。(第三方接口、臨時重構遺留代碼,完整的文章在這裏

List list = new LinkedList();
List spy = spy(list);

//optionally, you can stub out some methods:
// 你可以爲某些函數打樁
when(spy.size()).thenReturn(100);

//using the spy calls *real* methods
// 通過spy對象調用真實對象的函數
spy.add("one");
spy.add("two");

//prints "one" - the first element of a list
// 輸出第一個元素
System.out.println(spy.get(0));

//size() method was stubbed - 100 is printed
// 因爲size()函數被打樁了,因此這裏返回的是100
System.out.println(spy.size());

//optionally, you can verify
// 交互驗證
verify(spy).add("one");
verify(spy).add("two");

理解監控真實對象非常重要!

有時,在監控對象上使用when(Object)來進行打樁是不可能或者不切實際的。因此,當使用監控對象時請考慮doReturn|Answer|Throw()函數族來進行打樁。例如 :

List list = new LinkedList();
List spy = spy(list);

//Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
// 不可能 : 因爲當調用spy.get(0)時會調用真實對象的get(0)函數,此時會發生IndexOutOfBoundsException異常,因爲真實List對象是空的
   when(spy.get(0)).thenReturn("foo");

//You have to use doReturn() for stubbing
// 你需要使用doReturn()來打樁
doReturn("foo").when(spy).get(0);

Mockito並不會爲真實對象代理函數調用,實際上它會拷貝真實對象。因此如果你保留了真實對象並且與之交互,不要期望從監控對象得到正確的結果。當你在監控對象上調用一個沒有被stub的函數時並不會調用真實對象的對應函數,你不會在真實對象上看到任何效果。

因此結論就是 : 當你在監控一個真實對象時,你想在stub這個真實對象的函數,那麼就是在自找麻煩。或者你根本不應該驗證這些函數。

14. 修改沒有測試樁的調用的默認返回值 ( 1.7版本之後 )

你可以指定策略來創建mock對象的返回值。這是一個高級特性,通常來說,你不需要寫這樣的測試。然後,它對於遺留系統來說是很有用處的。當你不需要爲函數調用打樁時你可以指定一個默認的answer。

Foo mock = mock(Foo.class, Mockito.RETURNS_SMART_NULLS);
Foo mockTwo = mock(Foo.class, new YourOwnAnswer());

關於RETURNS_SMART_NULLS更多的信息請查看 :
RETURNS_SMART_NULLS文檔

15. 爲下一步的斷言捕獲參數 (1.8版本之後)

Mockito以java代碼風格的形式來驗證參數值 : 即通過使用equals()函數。這也是我們推薦用於參數匹配的方式,因爲這樣會使得測試代碼更簡單、簡潔。在某些情況下,當驗證交互之後要檢測真實的參數值時這將變得有用。例如 :

ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
// 參數捕獲
verify(mock).doSomething(argument.capture());
// 使用equal斷言
assertEquals("John", argument.getValue().getName());

警告 : 我們建議使用沒有測試樁的ArgumentCaptor來驗證,因爲使用含有測試樁的ArgumentCaptor會降低測試代碼的可讀性,因爲captor是在斷言代碼塊之外創建的。另一個好處是它可以降低本地化的缺點,因爲如果測試樁函數沒有被調用,那麼參數就不會被捕獲。總之,ArgumentCaptor與自定義的參數匹配器相關(可以查看ArgumentMatcher類的文檔 )。這兩種技術都能用於檢測外部傳遞到Mock對象的參數。然而,使用ArgumentCaptor在以下的情況下更合適 :

  • 自定義不能被重用的參數匹配器
  • 你僅需要斷言參數值

自定義參數匹配器相關的資料你可以參考ArgumentMatcher文檔。

16. 真實的局部mocks (1.8版本之後)

在內部通過郵件進行了無數爭辯和討論後,最終 Mockito 決定支持部分測試,早前我們不支持是因爲我們認爲部分測試會讓代碼變得糟糕。然而,我們發現了部分測試真正合理的用法。詳情點這

在 Mockito 1.8 之前,spy() 方法並不會產生真正的部分測試,而這無疑會讓一些開發者困惑。更詳細的內容可以看:這裏Java 文檔

    //you can create partial mock with spy() method:
    List list = spy(new LinkedList());

    //you can enable partial mock capabilities selectively on mocks:
    Foo mock = mock(Foo.class);
    //Be sure the real implementation is 'safe'.
    //If real implementation throws exceptions or depends on specific state of the object then you're in trouble.
    when(mock.someMethod()).thenCallRealMethod();

一如既往,你會去讀部分測試的警告部分:面向對象編程通過將抽象的複雜度拆分爲一個個獨立,精確的 SRPy 對象中,降低了抽象處理的複雜度。那部分測試是怎麼遵循這個規範的呢?事實上部分測試並沒有遵循這個規範……部分測試通常意味着抽象的複雜度被移動到同一個對象的不同方法中,在大多數情況下,這不會是你想要的應用架構方式。

然而,在一些罕見的情況下部分測試纔會是易用的:處理不能輕易修改的代碼(第三方接口,臨時重構的遺留代碼等等)。然而,爲了新的,測試驅動和架構優秀的代碼,我是不會使用部分測試的。

17. 重置mocks對象 (1.8版本之後)

聰明的 Mockito 使用者很少會用到這個特性,因爲他們知道這是出現糟糕測試單元的信號。通常情況下你不會需要重設你的測試單元,只需要爲每一個測試方法重新創建一個測試單元就可以了。

如果你真的想通過 reset() 方法滿足某些需求的話,請考慮實現簡單,小而且專注於測試方法而不是冗長,精確的測試。首先可能出現的代碼異味就是測試方法中間那的 reset() 方法。這可能意味着你已經過度測試了。請遵循測試方法的呢喃:請讓我們小,而且專注於單一的行爲上。在 Mockito 郵件列表中就有好幾個討論是和這個有關的。

添加 reset() 方法的唯一原因就是讓它能與容器注入的測試單元協作。詳情看 issue 55FAQ

別自己給自己找麻煩,reset() 方法在測試方法的中間確實是代碼異味。

   List mock = mock(List.class);
   when(mock.size()).thenReturn(10);
   mock.add(1);

   reset(mock);
   //at this point the mock forgot any interactions & stubbing

18. 故障排查與驗證框架的使用 (1.8版本之後)

首先,如果出現了任何問題,我建議你先看 Mockito FAQ

任何你提的問題都會被提交到 Mockito 的郵件列表中。

然後你應該知道 Mockito 會驗證你是否始終以正確的方式使用它,對此有疑惑的話不妨看看 validateMockitoUsage() 的文檔說明。

19.行爲驅動開發的別名 (1.8版本之後)

行爲驅動開發實現測試單元的模式將 //given //when //then comments 視作測試方法的基礎,這也是我們實現單元測試時被建議做的!

你可以在這開始學習有關 BDD 的知識

問題是當信息沒有很好地與 //given //when //then comments 交互時,扮演規範角色的測試樁 API 就會出現問題。這是因爲測試樁屬於給定測試單元的組件,而且不是任何測試的組件。因此 BDDMockito 類介紹了一個別名,使你的測試樁方法調用 BDDMockito.given(Object) 方法。現在它可以很好地和給定的 BDD 模式的測試單元組件進行交互。

 import static org.mockito.BDDMockito.*;

 Seller seller = mock(Seller.class);
 Shop shop = new Shop(seller);

 public void shouldBuyBread() throws Exception {
   //given
   given(seller.askForBread()).willReturn(new Bread());

   //when
   Goods goods = shop.buyBread();

   //then
   assertThat(goods, containBread());
 }

20. 序列化mock對象

模擬對象可以被序列化。有了這個特性你就可以在依賴被序列化的情況下使用模擬對象了。

警告:這個特性很少在單元測試中被使用。

To create serializable mock use MockSettings.serializable():

這個特性通過 BDD 擁有不可考外部依賴的特性的具體用例實現,來自外部依賴的 Web 環境和對象會被序列化,然後在不同層之間被傳遞。

   List serializableMock = mock(List.class, withSettings().serializable());

The mock can be serialized assuming all the normal serialization requirements are met by the class.

模擬對象能被序列化假設所有普通的序列化要求都被類滿足了。

讓一個真實的偵查對象可序列化需要多一些努力,因爲 spy(…) 方法沒有接收 MockSettings 的重載版本。不過不用擔心,你幾乎不可能用到這。

 List<Object> list = new ArrayList<Object>();
 List<Object> spy = mock(ArrayList.class, withSettings()
                 .spiedInstance(list)
                 .defaultAnswer(CALLS_REAL_METHODS)
                 .serializable());

21. 新的註解 : @Captor,@Spy,@ InjectMocks (1.8.3版本之後)

V1.8.3 帶來的新註解在某些場景下可能會很實用

@Captor 簡化 ArgumentCaptor 的創建 - 當需要捕獲的參數是一個令人討厭的通用類,而且你想避免編譯時警告。

@Spy - 你可以用它代替 spy(Object) 方法

@InjectMocks - 自動將模擬對象或偵查域注入到被測試對象中。需要注意的是 @InjectMocks 也能與 @Spy 一起使用,這就意味着 Mockito 會注入模擬對象到測試的部分測試中。它的複雜度也是你應該使用部分測試原因。

所有新的註解僅僅在 MockitoAnnotations.initMocks(Object) 方法中被處理,就像你在 built-in runner 中使用的 @Mock 註解:MockitoJUnitRunner 或 規範: MockitoRule.

22. 驗證超時 (1.8.5版本之後)

允許帶有暫停的驗證。這使得一個驗證去等待一段特定的時間,以獲得想要的交互而不是如果還沒有發生事件就帶來的立即失敗。在併發條件下的測試這會很有用。

感覺起來這個特性應該很少被使用 - 指出更好的測試多線程系統的方法。

還沒有實現去和 InOrder 驗證協作。

例子:

   //passes when someMethod() is called within given time span
   verify(mock, timeout(100)).someMethod();
   //above is an alias to:
   verify(mock, timeout(100).times(1)).someMethod();

   //passes when someMethod() is called *exactly* 2 times within given time span
   verify(mock, timeout(100).times(2)).someMethod();

   //passes when someMethod() is called *at least* 2 times within given time span
   verify(mock, timeout(100).atLeast(2)).someMethod();

   //verifies someMethod() within given time span using given verification mode
   //useful only if you have your own custom verification modes.
   verify(mock, new Timeout(100, yourOwnVerificationMode)).someMethod();

23. 自動初始化被@Spies, @InjectMocks註解的字段以及構造函數注入 (1.9.0版本之後)

Mockito 現在會通過注入構造方法、setter 或域注入儘可能初始化帶有 @Spy 和 @InjectMocks 註解的域或方法。

爲了利用這一點特性,你需要使用 MockitoAnnotations.initMocks(Object), MockitoJUnitRunnerMockitoRule

爲了 InjectMocks 請在 Java 文檔中瞭解更多可用的技巧和注入的規範

 //instead:
 @Spy BeerDrinker drinker = new BeerDrinker();
 //you can write:
 @Spy BeerDrinker drinker;

 //same applies to @InjectMocks annotation:
 @InjectMocks LocalPub;

24. 單行測試樁 (1.9.0版本之後)

Mockito 現在允許你在使用測試樁時創建模擬對象。基本上,它允許在一行代碼中創建一個測試樁,這對保持代碼的整潔很有用。舉例來說,有些乏味的測試樁會被創建,並在測試初始化域時被打入,例如:

 public class CarTest {
   Car boringStubbedCar = when(mock(Car.class).shiftGear()).thenThrow(EngineNotStarted.class).getMock();

   @Test public void should... {}

25. 驗證被忽略的測試樁 (1.9.0版本之後)

Mockito 現在允許爲了驗證無視測試樁。在與 verifyNoMoreInteractions() 方法或驗證 inOrder() 方法耦合時,有些時候會很有用。幫助避免繁瑣的打入測試樁調用驗證 - 顯然我們不會對驗證測試樁感興趣。

警告,ignoreStubs() 可能會導致 verifyNoMoreInteractions(ignoreStubs(…)) 的過度使用。謹記在心,Mockito 沒有推薦用 verifyNoMoreInteractions() 方法連續地施用於每一個測試中,原因在 Java 文檔中有。

一些例子:

 verify(mock).foo();
 verify(mockTwo).bar();

 //ignores all stubbed methods:
 verifyNoMoreInvocations(ignoreStubs(mock, mockTwo));

 //creates InOrder that will ignore stubbed
 InOrder inOrder = inOrder(ignoreStubs(mock, mockTwo));
 inOrder.verify(mock).foo();
 inOrder.verify(mockTwo).bar();
 inOrder.verifyNoMoreInteractions();

更好的例子和更多的細節都可以在 Java 文檔的 ignoreStubs(Object…) 部分看到。

26. mock詳情 (1.9.5版本之後)

爲了區別一個對象是模擬對象還是偵查對象:

     Mockito.mockingDetails(someObject).isMock();
     Mockito.mockingDetails(someObject).isSpy();

MockingDetails.isMock()MockingDetails.isSpy() 方法都會返回一個布爾值。因爲一個偵查對象只是模擬對象的一種變種,所以 isMock() 方法在對象是偵查對象是會返回 true。在之後的 Mockito 版本中 MockingDetails 會變得更健壯,並提供其他與模擬對象相關的有用信息,例如:調用,測試樁信息,等等……

27. 委託調用真實實例 (Since 1.9.5)

使用常規的 spy API 去 mock 或者 spy 一個對象很困難時可以用 delegate 來 spy 或者 mock 對象的某一部分。
從 Mockito 的 1.10.11 版本開始, delegate 有可能和 mock 的類型相同也可能不同。如果不是同一類型,
delegate 類型需要提供一個匹配方法否則就會拋出一個異常。下面是關於這個特性的一些用例:

  • 帶有 interface 的 final 類
  • 已經自定義代理的對象
  • 帶有 finalize 方法的特殊對象,就是避免重複執行。

和常規 spy 的不同:

  • 標準的 spy (spy(Object)) 包含被 spy 實例的所有狀態信息,方法在 spy 對象上被調用。被 spy 的對象只在 mock
    創建時被用來拷貝狀態信息。如果你通過標準 spy 調用一個方法,這個 spy 會調用其內部的其他方法記錄這次操作,
    以便後面驗證使用。等效於存根 (stubbed)操作。

  • mock delegates 只是簡單的把所有方法委託給 delegate。delegate 一直被當成它代理的方法使用。如果你
    從一個 mock 調用它被委託的方法,它會調用其內部方法,這些調用不會被記錄,stubbing 在這裏也不會生效。
    Mock 的 delegates 相對於標準的 spy 來說功能弱了很多,不過在標準 spy 不能被創建的時候很有用。

更多信息可以看這裏 AdditionalAnswers.delegatesTo(Object).


28. MockMaker API (Since 1.9.5)

爲了滿足用戶的需求和 Android 平臺使用。Mockito 現在提供一個擴展點,允許替換代理生成引擎。默認情況下,Mockito 使用 cglib 創建動態代理。

這個擴展點是爲想要擴展 Mockito 功能的高級用戶準備的。比如,我們現在就可以在 dexmaker 的幫助下使用 Mockito
測試 Android。

更多的細節,原因和示例請看 MockMaker 的文檔。


29. (new) BDD 風格的驗證 (Since 1.10.0)

開啓 Behavior Driven Development (BDD) 風格的驗證可以通過 BBD 的關鍵詞 then 開始驗證。

 given(dog.bark()).willReturn(2);

 // when
 ...

 then(person).should(times(2)).ride(bike);

更多信息請查閱 BDDMockito.then(Object) .


30. (new) Spying 或 mocking 抽象類 (Since 1.10.12)

現在可以方便的 spy 一個抽象類。注意,過度使用 spy 或許意味着代碼的設計上有問題。(see spy(Object)).

之前,spying 只可以用在實例對象上。而現在新的 API 可以在創建一個 mock 實例時使用構造函數。這對 mock
一個抽象類來說是很重要的,這樣使用者就不必再提供一個抽象類的實例了。目前的話只支持無參構造函數,
如果你認爲這樣還不夠的話歡迎向我們反饋。

//convenience API, new overloaded spy() method:
 SomeAbstract spy = spy(SomeAbstract.class);

 //Robust API, via settings builder:
 OtherAbstract spy = mock(OtherAbstract.class, withSettings()
    .useConstructor().defaultAnswer(CALLS_REAL_METHODS));

 //Mocking a non-static inner abstract class:
 InnerAbstract spy = mock(InnerAbstract.class, withSettings()
    .useConstructor().outerInstance(outerInstance).defaultAnswer(CALLS_REAL_METHODS));

更多信息請見 MockSettings.useConstructor() .


31. (new) Mockito mocks 可以通過 classloaders 序列化/反序列化 (Since 1.10.0)

Mockito 通過 classloader 引入序列化。和其他形式的序列化一樣,所有 mock 層的對象都要被序列化,
包括 answers。因爲序列化模式需要大量的工作,所以這是一個可選擇設置。

// 常規的 serialization
mock(Book.class, withSettings().serializable());

// 通過 classloaders 序列化
mock(Book.class, withSettings().serializable(ACROSS_CLASSLOADERS));

更多信息請查看 MockSettings.serializable(SerializableMode).


32. (new) Deep stubs 更好的泛型支持 (Since 1.10.0)

Deep stubbing 現在可以更好的查找類的泛型信息。這就意味着像這樣的類
不必去 mock 它的行爲就可以使用。

class Lines extends List<Line> {
     // ...
 }

 lines = mock(Lines.class, RETURNS_DEEP_STUBS);

 // Now Mockito understand this is not an Object but a Line
 Line line = lines.iterator().next();

請注意,大多數情況下 mock 返回一個 mock 對象是錯誤的。


33. (new) Mockito JUnit rule (Since 1.10.17)

Mockito 現在提供一個 JUnit rule。目前爲止,有兩種方法可以初始化 fields ,使用 Mockito 提供的註解比如
@Mock, @Spy, @InjectMocks 等等。

現在你可以選擇使用一個 rule:

 @RunWith(YetAnotherRunner.class)
 public class TheTest {
     @Rule public MockitoRule mockito = MockitoJUnit.rule();
     // ...
 }

更多信息到這裏查看 MockitoJUnit.rule().


34. (new) 開啓和關閉 plugins (Since 1.10.15)

這是一個測試特性,可以控制一個 mockito-plugin 開啓或者關閉。詳情請查看 PluginSwitch


35. 自定義驗證失敗信息 (Since 2.0.0)

允許聲明一個在驗證失敗時輸出的自定義消息
示例:

 // will print a custom message on verification failure
 verify(mock, description("This will print on failure")).someMethod();

 // will work with any verification mode
 verify(mock, times(2).description("someMethod should be called twice")).someMethod();

字段摘要

類型 字段以及描述
static Answer< Object > CALLS_REAL_METHODS
用於mock(Class, Answer)的可選參數Answer

字段詳情

**CALLS_REAL_METHODS**
public static final Answer CALLS_REAL_METHODS

用於mock(Class, Answer)的可選參數Answer

Answer可以用於定義unstubbed invocations的返回值.

這個Answer接口對於legacy code非常有用. 當使用這個接口的時候, unstubbed methods會被實現.
這是一種通過調用默認方法來創建partial mock對象的方式。

通常,你將要閱讀mock的部分警告:Object oriented programming is more less tackling complexity by dividing the complexity into separate, specific, , SRPy objects.
partial mock是如果適應這種模式的呢?好吧!它不僅僅是,partial mock通常意味着複雜性在同一個對象中移動到不同的方法.在大多數情況下,這不是你想要的設計你的應用的方式。

然而,當partial mocks派上用場同樣也有少許情況:處理你不易改變的代碼(第三方接口,legacy code的臨時重構).我將不使用partial mocks用於新的、測試驅動以及設計不錯的代碼。


例如:

Foo mock = mock(Foo.class, CALLS_REAL_METHODS);

// this calls the real implementation of Foo.getSomething()
value = mock.getSomething();

when(mock.getSomething()).thenReturn(fakeValue);

// now fakeValue is returned
value = mock.getSomething();

方法摘要

Modifier and Type Method and Description
static VerificationAfterDelay after(long millis)
給定的時間後進行驗證
static VerificationMode atLeast(int minNumberOfInvocations)
至少進行minNumberOfInvocations次驗證
static VerificationMode atLeastOnce()
至少進行一次驗證
static VerificationMode atMost(int maxNumberOfInvocations)
最多進行maxNumberOfInvocations次驗證
static VerificationMode calls(int wantedNumberOfInvocations)
允許順序進行non-greedy驗證

方法詳情

after

	public static VerificationAfterDelay after(long millis)

在給定的時間後進行驗證。它會爲了預期的效果進行等待一段時間後進行驗證,而不是因爲沒發生而立即失敗。這可能對於測試多併發條件非常有用。

after()等待整個週期的特點不同於timeout(),而timeout()一旦驗證通過就儘快停止,例如:當使用times(2)可以產生不同的行爲方式,可能通過後過會又失敗。這種情況下,timeout只要times(2)通過就會通過,然後after執行完整個週期時間,可能會失敗,也意味着times(2)也失敗。

感覺這個方法應該少使用——找到更好的方法測試你的多線程系統。

對尚未實現的工作進行驗證。


	//passes after 100ms, if someMethod() has only been called once at that time.<br>
	verify(mock, after(100)).someMethod();<br>
	//above is an alias to:<br>
	verify(mock, after(100).times(1)).someMethod();

	//passes if someMethod() is called *exactly* 2 times after the given timespan
	verify(mock, after(100).times(2)).someMethod();

	//passes if someMethod() has not been called after the given timespan<br>
	verify(mock, after(100).never()).someMethod();

	//verifies someMethod() after a given time span using given verification mode
	//useful only if you have your own custom verification modes.
	verify(mock, new After(100, yourOwnVerificationMode)).someMethod();

參照Mockito類的javadoc幫助文檔中的例子

Parameters:

  • millis - - time span in milliseconds

Returns:

  • verification mode

atLeast

	public static VerificationMode atLeast(int minNumberOfInvocations)

允許至少進行x次驗證。例如:

	verify(mock, atLeast(3)).someMethod("some arg");

參照Mockito類的javadoc幫助文檔中的例子

Parameters:

  • minNumberOfInvocations - invocations的最小次數

Returns:

  • verification mode

atLeastOnce

	public static VerificationMode atLeastOnce()

至少進行一次一次驗證。例如:

	verify(mock, atLeastOnce()).someMethod("some arg");

atLeast(1)的別名.
參照Mockito類的javadoc幫助文檔中的例子

Returns:

  • verification mode

atMost

	public static VerificationMode atMost(int maxNumberOfInvocations)

至多進行x次驗證. 例如:

	verify(mock, atMost(3)).someMethod("some arg");

參照Mockito類的javadoc幫助文檔中的例子

Parameters::

  • maxNumberOfInvocations - invocations的最大次數

Returns:

  • verification mode

##calls

	public static VerificationMode calls(int wantedNumberOfInvocations)

允許順序進行non-greedy驗證. 例如:

	inOrder.verify( mock, calls( 2 )).someMethod( "some arg" );
  • 如果這個方法調用3次不會失敗,不同於times(2)
  • 不會標記第三次驗證,不同於atLeast(2)
這個verification mode只能用於順序驗證.

Parameters::

  • wantedNumberOfInvocations - 驗證的次數

Returns:

  • verification mode

繼承org.mockito.Matchers的方法

any

	public static <T> T any()<br><br>

匹配任何值,包括null

anyObject()的別名

參照Matchers類的javadoc幫助文檔中的例子

這是: anyObject() and any(java.lang.Class)的別名

Returns:

  • null

any

	public static <T> T any(Class<T> clazz)

匹配任何對象,包括null

這個方法不進行給定參數的類型檢查,它就是爲了避免代碼中的強制轉換(Casting)。然而這可能會改變(類型檢查可以添加)將來的主要版本。

參照Matchers類的javadoc幫助文檔中的例子

這是: anyObject() and any(java.lang.Class)的別名

Returns:

  • null

anyBoolean

	public static boolean anyBoolean()

任何boolean類型或非空(non-null)的Boolean.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

  • false

anyByte

	public static byte anyByte()

任何byte類型變量或非空(non-null)Byte.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

  • 0

anyChar

	public static char anyChar()

任何char類型變量或非空(non-null)的Character.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

  • 0

anyCollection

public static Collection anyCollection()

任何非空(non-null)的Collection.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

  • 空Collection.

anyCollectionOf

public static < T > Collection < T > anyCollectionOf(Class<T> clazz)

通用友好的別名anyCollection()。爲了保持代碼清潔,通過@SuppressWarnings(“unchecked”)來進行替代編譯器警告。

任何非空(non-null)Collection.

這個方法不進行給定參數的類型檢查,它就是爲了避免代碼中的強制轉換(Casting)。然而這可能會改變(類型檢查可以添加)將來的主要版本。

參照Matchers類的javadoc幫助文檔中的例子

Parameters

  • clazz - 類型屬於Collection類型避免類型轉換(Casting)

Returns:

  • 空Collection.

anyDouble

	public static double anyDouble()

任何double類型或非空(non-null)的Double.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

anyFloat

	public static float anyFloat()

任何float類型或非空(non-null)Float.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

anyInt

	public static int anyInt()

任何int或非空(non-null)Integer.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

anyList

public static List anyList()

任何非空(non-null)List.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

  • 空List.

anyListOf

public static < T >  List < T > anyListOf(Class< T > clazz)

通用友好的別名anyList()。爲了保持代碼清潔,通過@SuppressWarnings(“unchecked”)來進行替代編譯器警告。

任何非空(non-null)List.

這個方法不進行給定參數的類型檢查,它就是爲了避免代碼中的強制轉換(Casting)。然而這可能會改變(類型檢查可以添加)將來的主要版本。

參照Matchers類的javadoc幫助文檔中的例子

Parameters:

  • clazz - 類型屬於List類型避免類型轉換(Casting)

Returns:

  • 空List.

anyLong

	public static long anyLong()

任何long類型或非空(non-null)Long.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

anyMap

public static Map anyMap()

任何非空(non-null)Map.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

  • 空Map.

anyMapOf

public static < K,V> Map < K,V> anyMapOf(Class< K> keyClazz, Class< V> valueClazz)

通用友好的別名anyMap()。爲了保持代碼清潔,通過@SuppressWarnings(“unchecked”)來進行替代編譯器警告。

任何非空(non-null)Map.

這個方法不進行給定參數的類型檢查,它就是爲了避免代碼中的強制轉換(Casting)。然而這可能會改變(類型檢查可以添加)將來的主要版本。

參照Matchers類的javadoc幫助文檔中的例子

Parameters:

  • keyClazz - map key類型避免類型強制轉換(Casting)
  • valueClazz - value類型避免類型強制轉換(Casting)

Returns:

  • 空Map.

anyObject

public static < T> T anyObject()

匹配任何事物, 包含null.

這是: any()和any(java.lang.Class)的別名

參照Matchers類的javadoc幫助文檔中的例子

Returns:

  • empty null.

anySet**

public static <a href="http://docs.oracle.com/javase/8/docs/api/java/util/Set.html?is-external=true">Set</a> anySet()

任何非空(non-null)Set.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

  • 空Set.

anySetOf

public static < T> Set < T> anySetOf(Class< T> clazz)

通用友好的別名anySet()。爲了保持代碼清潔,通過@SuppressWarnings(“unchecked”)來進行替代編譯器警告。

任何非空(non-null)Set.

這個方法不進行給定參數的類型檢查,它就是爲了避免代碼中的強制轉換(Casting)。然而這可能會改變(類型檢查可以添加)將來的主要版本。

參照Matchers類的javadoc幫助文檔中的例子

Parameters:

  • clazz - 類型屬於Set爲了避免類型強制轉換(Casting)

Returns:

  • 空Set.

anyShort

	public static short anyShort()

任何short類型或非空(non-null)Short.

參照Matchers類的javadoc幫助文檔中的例子

Returns:

anyString

	public static String anyString()

任何非空(non-null)String

參照Matchers類的javadoc幫助文檔中的例子

Returns:

  • 空String ("").

anyVararg

	public static < T> T anyVararg()

任何vararg類型, 即任何參數(arguments)的number和values

例如:


	//verification:
	mock.foo(1, 2);
	mock.foo(1, 2, 3, 4);
	verify(mock, times(2)).foo(anyVararg());

	//stubbing:
	when(mock.foo(anyVararg()).thenReturn(100);

	//prints 100
	System.out.println(mock.foo(1, 2));
	//also prints 100<
	System.out.println(mock.foo(1, 2, 3, 4));

參照Matchers類的javadoc幫助文檔中的例子

Returns:

  • null.

argThat

public static < T> T argThat(ArgumentMatcher < T> matcher)

允許創建自定義的參數匹配模式.這個API在2.0中已經改變,請閱讀ArgumentMatcher基礎指南。

在實現自定義參數匹配模式前,理解使用的場景和non-trivial參數的可用選項是非常重要的。這種方式下,你可以在給定的情況下選擇最好的方法來設計製造高質量的測試(清潔和維護).請閱讀ArgumentMatcher文檔學習方法和例子。

在極少數情況下,當參數是基本數據類型(primitive)時,你必須使用相關的intThat()、floatThat()等方法。這些方法在進行自動拆箱(auto-unboxing)時可以避免NullPointerException異常。

參照ArgumentMatcher類的javadoc幫助文檔中的例子

Parameters:

  • matcher - 取決於選擇的參數匹配模式(argument matches)

Returns:

  • null.

##booleanThat

public static boolean booleanThat(ArgumentMatcher < Boolean> matcher)

允許創建自定義的Boolean類型參數匹配模式(Boolean argument matchers).

參照Matchers類的javadoc幫助文檔中的例子

Parameters:

  • matcher - 取決於選擇的參數匹配模式(argument matches)
    Returns:

  • false.

##byteThat

public static byte byteThat(ArgumentMatcher < Byte> matcher)

允許創建自定義的Byte類型參數匹配模式(Byte argument matchers)

參照Matchers類的javadoc幫助文檔中的例子

Parameters:

  • matcher - 取決於選擇的參數匹配模式(argument matches)

Returns:

##charThat

public static char charThat(ArgumentMatcher < Character> matcher)

允許創建自定義的Character類型參數匹配模式(Character argument matchers)

參照Matchers類的javadoc幫助文檔中的例子

Parameters:

  • matcher - 取決於選擇的參數匹配模式(argument matches)

Returns:

contains

	public static String contains(String substring)

String參數包含給定的substring字符串.

參照Matchers類的javadoc幫助文檔中的例子

Parameters:

  • substring - substring字符串.

Returns:

  • 空String ("").

##description函數

public static VerificationMod description(String description)

添加驗證失敗時要輸出的文字內容


verify(mock, description("This will print on failure")).someMethod("some arg");

Parameters:

輸出的文字內容

Returns:

驗證模式

Since:

  • 2.0.0

##doAnswer函數

public static Stubber doAnswer(Answer answer)

當你想要測試一個無返回值的函數時,可以使用一個含有泛型類Answer參數的doAnswer()函數。爲無返回值的函數做測試樁與when(Objecy)方法不同,因爲編譯器不喜歡在大括號內使用void函數。


doAnswer(new Answer() {
      public Object answer(InvocationOnMock invocation) {
          Object[] args = invocation.getArguments();
          Mock mock = invocation.getMock();
          return null;
      }})
  .when(mock).someMethod();

參照Mockito類的javadoc幫助文檔中的例子

Parameters:

測試函數的應答內容

Returns:

測試方法的測試樁


##doCallRealMethod函數

public static Stubber doCallRealMethod()

如果你想調用某一個方法的真實實現請使用doCallRealMethod()

像往常一樣你需要閱讀局部的mock對象警告:面向對象編程通過將複雜的事物分解成單獨的、具體的、SRPY對象來減少對複雜事件的處理。
局部模擬是如何符合這種範式的呢。?局部模擬通常情況下是指在對象相同的情況下那些複雜的事物被移動另一個不同的方法中。在大多數情況下,並沒有按照你所希望的方式來設計你的應用。

然而,使用局部mock對象也會有個別情況:有些代碼你並不能非常容易的改變(3rd接口,臨時遺留代碼的重構等),但是我對於新的、測試驅動及良好設計的代碼不會使用局部mock對象。

同樣在javadoc中spy(Object)閱讀更多關於partial mocks的說明.推薦使用Mockito.spy()來創建局部mock對象原因是由於你負責構建對象並傳值到spy()中,它只管保證被調用。


Foo mock = mock(Foo.class);
   doCallRealMethod().when(mock).someVoidMethod();

   // this will call the real implementation of Foo.someVoidMethod()
   // 調用Foo.someVoidMethod()的真實現
   mock.someVoidMethod();

參照Mockito類的javadoc幫助文檔中的例子

Returns:

測試方法的測試樁

Since:

  • 1.9.5

##doNothing函數

public static Stubber doNothing()

使用doNothing()函數是爲了設置void函數什麼也不做。需要注意的是默認情況下返回值爲void的函數在mocks中是什麼也不做的但是,也會有一些特殊情況。

1.測試樁連續調用一個void函數


doNothing().
   doThrow(new RuntimeException())
   .when(mock).someVoidMethod();

   //does nothing the first time:
   //第一次才能都沒做
   mock.someVoidMethod();

   //throws RuntimeException the next time:
   //一下次拋出RuntimeException
   mock.someVoidMethod();

2.當你監控真實的對象並且你想讓void函數什麼也不做:


List list = new LinkedList();
   List spy = spy(list);

   //let's make clear() do nothing
   doNothing().when(spy).clear();

   spy.add("one");

   //clear() does nothing, so the list still contains "one"
   spy.clear();

參照Mockito類的javadoc幫助文檔中的例子

Returns:

stubber - 測試方法的測試樁


##doReturn函數

public static Stubber doReturn(Object toBeReturned)

在某些特殊情況下如果你無法使用when(Object)可以使用doReturn()函數

注意:對於測試樁推薦使用when(Object)函數,因爲它是類型安全的並且可讀性更強(特別是在測試樁連續調用的情況下)

都有哪些特殊情況下需要使用doReturn()

1.當監控真實的對象並且調用真實的函數帶來的影響時:

List list = new LinkedList();
   List spy = spy(list);

   //Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
   
   // 不能完成的:真實方法被調用所以spy.get(0)拋出IndexOutOfBoundsException(list仍是空的)
   when(spy.get(0)).thenReturn("foo");

   //You have to use doReturn() for stubbing:
   //你應用使用doReturn()函數
   doReturn("foo").when(spy).get(0);

  1. 重寫一個前exception-stubbing:

when(mock.foo()).thenThrow(new RuntimeException());

   //Impossible: the exception-stubbed foo() method is called so RuntimeException is thrown.
    // 不能完成的:exception-stubbed foo()被調用拋出RuntimeException異常
   when(mock.foo()).thenReturn("bar");

   //You have to use doReturn() for stubbing:
   //你應用使用doReturn()函數
   doReturn("bar").when(mock).foo();

上面的情況展示了Mockito’s的優雅語法。注意這些情況並不常見。監控應該是分散的並且重寫exception-stubbing也不常見。更何況對於指出測試樁並複寫測試樁是一種潛在的代碼嗅覺

參照Mockito類的javadoc幫助文檔中的例子

Parameters:

toBeReturned - 當測試樁函數被調用時要被返回的對象

Returns:

stubber - 測試方法的測試樁


##doThrow函數

public static Stubber doThrow(Class<? extends Throwable> toBeThrown)

當你想測試void函數中指定類的拋出異常時使用doThrow()

當每一個函數被調用時一個新的異常實例將會被創建

爲無返回值的函數做測試樁與when(Objecy)方法不同,因爲編譯器不喜歡在大括號內使用void函數。

doThrow(RuntimeException.class).when(mock).someVoidMethod();

Parameters:

測試方法被調用時返回的對象

Returns:

測試方法的測試樁

Since:

  • 1.9.0

##doThrow函數

public static Stubber doThrow(Throwable toBeThrown)

當測試一個void函數的異常時使用doThrow()

測試void函數需要與使用when(Object)不同的方式,因爲編譯器不喜歡大括號內有void函數

Example:

doThrow(RuntimeException.class).when(mock).someVoidMethod();

Parameters:

測試方法被調用時返回的對象

Returns:

測試方法的測試樁

Since:

  • 1.9.0

##ignoreStubs函數

public static Object[] ignoreStubs(Object... mocks)

忽略對驗證函數的測試,當與verifyNoMoreInteractions()成對出現或是驗證inOrder()時是很有用的。避免了在測試時的多餘驗證,實際上我們對驗證測試一點也不感興趣。

警告,ignoreStubs()可能會導致verifyNoMoreInteractions(ignoreStubs(...))的過度使用。考慮到Mockito並不推薦使用verifyNoMoreInteractions()函數轟炸每一個測試,這其中的原由在文檔verifyNoMoreInteractions(Object…)部分已經說明:換句話說在mocks中所有* stubbed * 的函數都被標記爲 * verified * 所以不需要使用這種方式。

該方法改變了input mocks!該方法只是爲了方便返回 imput mocks 。

忽略測試也會被忽略掉驗證inOrder,包括InOrder.verifyNoMoreInteractions(),看下面第二個示例:

Example:

//mocking lists for the sake of the example (if you mock List in real you will burn in hell)
  List mock1 = mock(List.class), mock2 = mock(List.class);

  //stubbing mocks:
  when(mock1.get(0)).thenReturn(10);
  when(mock2.get(0)).thenReturn(20);

  //using mocks by calling stubbed get(0) methods:
  
  // 調用stubbed get(0)使用mocks
  System.out.println(mock1.get(0)); //prints 10
  System.out.println(mock2.get(0)); //prints 20

  //using mocks by calling clear() methods:
  // 調用clear()使用mocks
  mock1.clear();
  mock2.clear();

  //verification:
  
  // 驗證
  verify(mock1).clear();
  verify(mock2).clear();

  //verifyNoMoreInteractions() fails because get() methods were not accounted for.
  
  // verifyNoMoreInteractions()會失敗,因爲get()未關聯賬號
  
  try { verifyNoMoreInteractions(mock1, mock2); } catch (NoInteractionsWanted e);

  //However, if we ignore stubbed methods then we can verifyNoMoreInteractions()
  //如要我們忽略測試函數我可以這樣verifyNoMoreInteractions()
  
  verifyNoMoreInteractions(ignoreStubs(mock1, mock2));

  //Remember that ignoreStubs() *changes* the input mocks and returns them for convenience.

忽略測試可以用於verification in order:

List list = mock(List.class);
  when(mock.get(0)).thenReturn("foo");

  list.add(0);
  System.out.println(list.get(0)); //we don't want to verify this
  list.clear();

  InOrder inOrder = inOrder(ignoreStubs(list));
  inOrder.verify(list).add(0);
  inOrder.verify(list).clear();
  inOrder.verifyNoMoreInteractions();

Parameters:

將被改變的input mocks

Returns:

和傳入參數一樣的mocks

Since:

1.9.0


##inOrder函數

public static InOrder inOrder(Object... mocks)

創建InOrder對象驗證 mocks in order

InOrder inOrder = inOrder(firstMock, secondMock);

inOrder.verify(firstMock).add("was called first");
inOrder.verify(secondMock).add("was called second");

驗證in order是很靈活的。你可以只驗證你感興趣的,並不需要一個一個驗證所有的交互。同樣你也可以創建InOrder對象只在相關in-order的驗證中進行傳值。

InOrder 驗證是’greedy’.你很難每一個都注意到。你可以在Mockito wiki pages頁搜索’greedy’獲取更多信息。

Mockito 1.8.4版本你能以order-sensitive方式調用verifyNoMoreInvocations(),閱讀更多InOrder.verifyNoMoreInteractions()

參照Mockito類的javadoc幫助文檔中的例子

Parameters:

in order中被修改的mocks

Returns:

in order中被用於驗證的InOrder對象


##mock函數

public static <T> T mock(Class <T> classToMock)

對給定的類或接口創建mock對象

Parameters:

需要mock的類或接口

Returns:

mock對象


##mock函數

public static <T> T mock(Class <T> classToMock, Answer defaultAnswer)

根據它對交互的迴應指明策略創建mock對象。這個是比較高級特性並且你不需要它寫多少測試代碼。但是對於legacy系統這是非常有用的。

這個是默認answer,所以當你不想測試函數時你可以使用它。


Foo mock = mock(Foo.class, RETURNS_SMART_NULLS);
Foo mockTwo = mock(Foo.class, new YourOwnAnswer());

參照Mockito類的javadoc幫助文檔中的例子

Parameters:

  • 需要mock的類或接口

  • 未測試函數的默認answer

Returns:

mock對象


##mock函數

public static <T> T mock(Class <T> classToMock, MockSettings mockSettings)

沒有標準的設置來創建mock對象

配置點的數目對mock的擴大有影響,所以我們在沒有越來越多重載Mockito.mock()的情況下需要一種更流利的方式來介紹一種新的配置方式。即MockSettings.


Listener mock = mock(Listener.class, withSettings()
     .name("firstListner").defaultBehavior(RETURNS_SMART_NULLS));
   );

使用它時需要小心一些並且不要常用。在什麼情況下你的測試會不需要標準配置的mocks?在測試代碼下太複雜以至於不需要標準配置的mocks?你有沒有重構測試代碼來讓它更加容易測試?

也可以參考withSettings()

參照Mockito類的javadoc幫助文檔中的例子

Parameters:

  • 需要mock的類或接口
  • mock配置

Returns:

  • mock對象

##mock

@Deprecated

@已過期

public static <T> T mock(Class <T> classToMock, ReturnValues returnValues)

已過期,請使用mock(Foo.class, defaultAnswer);

已過期,請使用mock(Foo.class, defaultAnswer);

mock(Class, Answer)

爲什麼會過期?爲了框架更好的一致性與交互性用Answer替換了ReturnValues。Answer接口很早就存在框架中了並且它有和ReturnValues一樣的責任。沒有必要維護兩個一樣的接口。

針對它的返回值需要指明策略來創建mock對象。這個是比較高級特性並且你不需要它寫多少測試代碼。但是對於legacy系統這是非常有用的。

明顯地,當你不需要測試方法時可以使用這個返回值。

Foo mock = mock(Foo.class, Mockito.RETURNS_SMART_NULLS);
Foo mockTwo = mock(Foo.class, new YourOwnReturnValues());

參照Mockito類的javadoc幫助文檔中的例子

Parameters:

  • 需要mock的類或接口
  • 未測試方法默認返回值

Returns:

  • mock對象

##mock

public static <T> T mock(Class <T> classToMock, String name)

指明mock的名字。命名mock在debug的時候非常有用。名字會在所有驗證錯誤中使用。需要注意的是對於使用太多mock或者collaborators的複雜代碼命名mock並不能解決問題。如果你使用了太多的mock,爲了更加容易測試/調試 你需要對其進行重構而不是對mock命名。

如果你使用了@Mock註解,意味着你的mock已經有名字了!

@Mock使用字段名稱作爲mock名字Read more

參照Mockito類的javadoc幫助文檔中的例子

Parameters:

  • 需要mock的類或接口
  • mock的名字

Returns:

  • mock對象

mockingDetails函數

public static MockingDetails mockingDetails(Object toInspect)

對於Mockito的關聯信息返回MockingDetails實例可以用於檢查某一特定的對象,無論給定的對象是mock還是監視的都可以被找出來。

在Mockito以後的版本中MockingDetails可能會擴大並且提供其它有用的有關mock的信息。e.g. invocations, stubbing info, etc.

Parameters:

  • 要檢查的對象。允許爲空

Returns:

MockingDetails實例

Since:

  • 1.9.5

n-w開頭的函數

never()函數

public static VerificationMode never()

相當於times(0),可參見 times(int)
驗證交互沒有發生. 例如:

verify(mock, never()).someMethod();

如果你想驗證mock之間沒有交互,可以使用verifyZeroInteractions(Object...) 或者 verifyNoMoreInteractions(Object...) 這兩個方法

具體例子可以參考Javadoc中的Mockito

Returns:

  • 驗證模式

only()函數

public static VerificationMode only()

如果當前mock的方法只被調用一次,則允許被檢驗。例如:


   verify(mock, only()).someMethod();
   //上面這行代碼是下面這兩行代碼的簡寫
   
   verify(mock).someMethod();
   verifyNoMoreInvocations(mock);

可以參考verifyNoMoreInteractions(Object...)方法

具體例子可以參考Javadoc中的Mockito

Returns:

  • verification mode

reset(T… mocks)函數

public static <T> void reset(T... mocks)

聰明的程序員很少會使用這個方法,因爲他們知道使用這個方法意味着這個測試寫的很low.通常情況下,你不需要重置你的mocks,你僅僅需要爲你的測試方法創建新的mocks就可以了。

你可以考慮寫一些簡單的、精悍的、聚焦的測試方法來代替reset()這個方法。當你在在測試方法的中間部分用到reset()這個方法時,說明你的測試方法太龐大了。

請遵循以下關於測試方法的建議:請保證你的測試方法在一個動作中短小、精悍、聚焦。在mockito的郵件列表中有很多關於這方面的主題討論。

我們添加reset()方法的唯一原因是使得注入容器的mocks得以有效的運行,具體可以參看issue 55 here or FAQ here

不要敗壞了你在程序員界的名聲,測試方法中間的reset()方法是代碼中的害羣之馬(這意味着你的這個測試方法太多)

   List mock = mock(List.class);
   when(mock.size()).thenReturn(10);
   mock.add(1);

   reset(mock);
   //此時會清除你之前所有的交互以及測試樁
     

Type Parameters:

  • T - mocks的類型

Parameters:

  • 被重置的mocks

spy(Class classToSpy)函數

@Incubating public static <T> T spy(Class<T> classToSpy)

請參考關於類spy的文檔,過渡使用spy會導致代碼變的非常糟糕。

相比與原來的spy(對象),這種方法可以在類的基礎上創建一個spy,而不是一個對象。有時你可以很方便基於類創建spy而避免提供一個spy對象的實例。

因爲他們不能被實例化,所以這個對於抽象類的監控非常有用。參見mocksettings.useconstructor()

例如:


   SomeAbstract spy = spy(SomeAbstract.class);

   //Robust API, via settings builder:
   //穩定的API,充過builder方式來設置
   
   OtherAbstract spy = mock(OtherAbstract.class, withSettings()
      .useConstructor().defaultAnswer(CALLS_REAL_METHODS));

   //Mocking a non-static inner abstract class:
   //模擬一個非靜態抽象內部類
   
   InnerAbstract spy = mock(InnerAbstract.class, withSettings()
      .useConstructor().outerInstance(outerInstance).defaultAnswer(CALLS_REAL_METHODS));
      

Type Parameters:

  • T - spy的類型

Parameters:

  • spy的類

Returns:

  • a spy of the provided class

Since:

  • 1.10.12

stub(T methodCall)函數

public static <T> DeprecatedOngoingStubbing<T> stub(T methodCall)

對一個方法打樁會返回結果值或者錯誤異常,例如:


 stub(mock.someMethod()).toReturn(10);

 //you can use flexible argument matchers, e.g:
 //你可以使用靈活的參數匹配,例如:
 
 stub(mock.someMethod(anyString())).toReturn(10);

 //setting exception to be thrown:
 //設置拋出的異常
 
 stub(mock.someMethod("some arg")).toThrow(new RuntimeException());

 //you can stub with different behavior for consecutive method calls.
 // 你可以對不同作用的連續回調的方法打測試樁:
 //Last stubbing (e.g: toReturn("foo")) determines the behavior for further consecutive calls.
 // 最後面的測試樁(例如:返回一個對象:"foo")決定了接下來的回調方法以及它的行爲。
 
 stub(mock.someMethod("some arg"))
  .toThrow(new RuntimeException())
  .toReturn("foo");
  

一些用戶有點混亂、混淆,是因爲相比於’stub()’,'when(Object)'更加被推薦

   //Instead of:
   //替代爲:
   stub(mock.count()).toReturn(10);

	//你可以這樣做:
   //You can do:
   when(mock.count()).thenReturn(10);

當對一個返回值爲空且拋出異常的方法打測試樁:doThrow(Throwable)測試樁會被重寫:例如通常測試樁會設置爲常用固定設置,但測試方法可以重寫它。切記重寫測試樁是一種非常不推薦的寫法,因爲這樣做會導致非常多的測試樁。

一旦這個方法打過樁,無論這個方法被調用多少次,這個方法會一直返回這個測試樁的值。

當你對相同的方法調用相同的參數打測試樁很多次,最後面的測試樁則非常重要

儘管我們可以去驗證對測試樁的調用,但通常它都是多餘的。比如說你對foo.bar()打測試樁。如果你比較關心的是當某些情況foo.bar()中斷了(經常在verify()方法執行之前),此時會返回什麼。如果你的代碼不關心是get(0)會返回什麼那麼它就不應該被添加測試樁。如果你還不確定?看這裏

Parameters:

  • methodCall - 調用的方法

Returns:

  • DeprecatedOngoingStubbing 對象是用來設置測試樁的值或者異常的

stubVoid(T mock)函數

public static <T> VoidMethodStubbable<T> stubVoid(T mock)

已廢棄.使用doThrow(Throwable)方法代替去打空測試樁

	//Instead of:
	//替代爲:
   stubVoid(mock).toThrow(e).on().someVoidMethod();

   //Please do:
   //請這樣做:
   doThrow(e).when(mock).someVoidMethod();
 

doThrow()之所以取代了stubVoid()方法,是因爲它增加了和它的兄弟方法doAnswer()的可讀性以及一致性


 stubVoid(mock).toThrow(new RuntimeException()).on().someMethod();

 //you can stub with different behavior for consecutive calls.
 //你可以對不同作用的連續回調的方法打測試樁:
 //Last stubbing (e.g. toReturn()) determines the behavior for further consecutive calls.
 //最後面的測試樁(例如:`toReturn()`)決定了接下來的回調方法以及它的行爲。
 
 stubVoid(mock)
   .toThrow(new RuntimeException())
   .toReturn()
   .on().someMethod();

具體例子可以參考Javadoc中的Mockito

Parameters:

  • mock - to stub

Returns:

  • stubbable object that allows stubbing with throwable

timesout(long millis)函數

public static VerificationWithTimeout timeout(long millis)

允許驗證時使用timeout。它會在指定的時間後觸發你所期望的動作,而不是立即失敗,也許這個對併發條件下的測試非常有用。它和after()是有所有不同的,因爲after()會等候一個完整的時期,除非最終的測試結果很快就出來了(例如:當never()失敗了), 然而當驗證通過時,timeout()會快速地停止,當你使用times(2)時會產生不同的行爲。例如,當先通過然後失敗,在這種情況下,timeout將會當time(2)通過時迅速通過,然而after()將會一直運行直到times(2)失敗,然後它也一同失敗。

這個功能看起來應該極少使用,但在多線程的系統的測試中,這是一個很好的方式

目前尚未實現按照順序去驗證


   //passes when someMethod() is called within given time span
   //當`someMethod()`被以時間段的形式調用時通過
    
   verify(mock, timeout(100)).someMethod();
   //above is an alias to:
   // 上面的是一個別名
   
   verify(mock, timeout(100).times(1)).someMethod();

   //passes as soon as someMethod() has been called 2 times before the given timeout
   // 在超時之前,`someMethod()`通過了2次調用
   verify(mock, timeout(100).times(2)).someMethod();

   //equivalent: this also passes as soon as someMethod() has been called 2 times before the given timeout
   //這個和上面的寫法是等價的,也是在超時之前,`someMethod()`通過了2次調用
   verify(mock, timeout(100).atLeast(2)).someMethod();

   //verifies someMethod() within given time span using given verification mode
   //在一個超時時間段內,用自定義的驗證模式去驗證`someMethod()`方法
   //useful only if you have your own custom verification modes.
   //只有在你有自己定製的驗證模式時纔有用
   
   verify(mock, new Timeout(100, yourOwnVerificationMode)).someMethod();

具體例子可以參考Javadoc中的Mockito

Parameters:

  • millis - - 時間長度(單位:毫秒)

Returns:

  • 驗證模式

time(int wantedNumberOfInvocations)函數

public static VerificationMode times(int wantedNumberOfInvocations)

允許驗證調用方法的精確次數,例如:

verify(mock, times(2)).someMethod("some arg");
//連續調用該方法兩次

具體例子可以參考Javadoc中的Mockito

Parameters:

  • wantedNumberOfInvocations - 希望調用的次數

Returns:

  • 驗證模式

validateMockitoUsage()函數

public static void validateMockitoUsage()

首頁,無論遇到任何問題,我都鼓勵你去閱讀the Mockito問答集:http://groups.google.com/group/mockito,你也可以在mockito郵件列表提問http://groups.google.com/group/mockito.

validateMockitoUsage()會明確地檢驗framework的狀態以用來檢查Mockito是否有效使用。但是,這個功能是可選的,因爲**'Mockito`會使這個用法一直有效**,不過有一個問題請繼續讀下去。

錯誤示例:

 //Oops, thenReturn() part is missing:
 //當心,`thenReturn()`部分是缺失的
 
 when(mock.get());

 //Oops, verified method call is inside verify() where it should be on the outside:
 //當心,下面驗證方法的調用在`verify()`裏面,其實應該在外面
 
 verify(mock.execute());

 //Oops, missing method to verify:
 //當心,驗證缺失方法
 
 verify(mock);

如果你錯誤的使用了Mockito,這樣將會拋出異常,這樣你就會知道你的測試是否寫的正確。你要清楚當你使用這個框架時,Mockito會接下來的所有時刻開始驗證(例如:下一次你驗證、打測試樁、調用mock等)。儘管在下一次測試中可能會拋出異常,但這個異常消息包含了一個完整棧蹤跡路徑以及這個錯誤的位置。此時你可以點擊並找到這個Mockito使用錯誤的地方。

有時,你可能想知道這個框架的使用方法。比如,一個用戶想將validateMockitoUsage()放在它的@after方法中,爲了能快速地知道它使用Mockito時哪裏錯了。如果沒有這個,它使用這個框架時將不能那麼迅速地知道哪裏使用錯了。另外在@after中使用validateMockitoUsage()比較好的一點是jUnit runner以及Junit rule中的測試方法在有錯誤時也會失敗,然而普通的next-time驗證可能會在下一次測試方法中才失敗。但是儘管Junit可能對下一次測試報告顯示紅色,但不要擔心,這個異常消息包含了一個完整棧蹤跡路徑以及這個錯誤的位置。此時你可以點擊並找到這個Mockito使用錯誤的地方。

同樣在runner中:MockitoJUnitRunner and ruleMockitoRule在每次測試方法之後運行validateMockitoUsage()

一定要牢記通常你不需要’validateMockitoUsage()'和框架驗證,因爲基於next-time觸發的應該已經足夠,主要是因爲可以點擊出錯位置查看強大的錯誤異常消息。但是,如果你已經有足夠的測試基礎(比如你爲所有的測試寫有自己的runner或者基類),我將會推薦你使用validateMockitoUsage(),因爲對@After添加一個特別的功能時將是零成本。

具體例子可以參考Javadoc中的Mockito

verify(T mock)函數

public static <T> T verify(T mock)

驗證發生的某些行爲
等同於verify(mock, times(1)) 例如:

   verify(mock).someMethod("some arg");

上面的寫法等同於:

   verify(mock, times(1)).someMethod("some arg");

參數比較是通過equals()方法。可參考ArgumentCaptor或者ArgumentMatcher中關於匹配以及斷言參數的方法。

儘管我們可以去驗證對測試樁的調用,但通常它都是多餘的。比如說你對foo.bar()打測試樁。如果你比較關心的是當某些情況foo.bar()中斷了(經常在verify()方法執行之前),此時會返回什麼。如果你的代碼不關心是get(0)會返回什麼那麼它就不應該被添加測試樁。如果你還不確定?看這裏

具體例子可以參考Javadoc中的Mockito

Parameters:

  • mock - 要被驗證的
    Returns:

  • mock本身

verifyNoMoreInteractions(Object… mocks)函數

public static void verifyNoMoreInteractions(Object... mocks)

檢查入參的mocks是否有任何未經驗證的交互,你可以在驗證你的mocks之後使用這個方法,用以確保你的mocks沒有其它地方會被調用.

測試柱的調用也被看成是交互。

**警告:**一些使用者,傾向於經常使用verifyNoMoreInteractions()方法做大量經典的、期望-運行-驗證的模擬,甚至是在所有的測試方法中使用。verifyNoMoreInteractions()並不被推薦於使用在所有的測試方法中。在交互測試工具中,verifyNoMoreInteractions()是一個很方便的斷言。你只能在當它是明確的、相關的時候使用它。濫用它將導致多餘的指定、不可維護的測試。你可以在這裏查找更多的文章。

這個方法會在測試方法運行之前檢查未經驗證的調用,例如:在setUp(),@Before方法或者構造函數中。考慮到要寫出良好優秀的代碼,交互只能夠在測試方法中。

示例:

 //interactions
 //交互
 mock.doSomething();
 mock.doSomethingUnexpected();

 //verification
 //驗證
 verify(mock).doSomething();

 //following will fail because 'doSomethingUnexpected()' is unexpected
 //因爲'doSomethingUnexpected()'是未被期望的,所以下面將會失敗
 verifyNoMoreInteractions(mock);

具體例子可以參考Javadoc中的Mockito

Parameters:

  • mocks - 被驗證的

verifyZeroInteractions(Object… mocks)函數

public static void verifyZeroInteractions(Object... mocks)

傳進來的mocks之間沒有任何交互。

   verifyZeroInteractions(mockOne, mockTwo);

這個方法會在測試方法運行之前檢查調用,例如:在setUp(),@Before方法或者構造函數中。考慮到要寫出良好的代碼,交互只能夠在測試方法中。

你也可以參考never()方法 - 這個方法很明確的表達了當前方法的用途.
具體例子可以參考Javadoc中的Mockito

Parameters:

  • mocks - 被驗證的

when(T methodCall)函數

public static <T> OngoingStubbing<T> when(T methodCall)

使測試樁方法生效。當你想讓這個mock能調用特定的方法返回特定的值,那麼你就可以使用它。
簡而言之:當你調用x方法時會返回y

when()是繼承自已經廢棄的方法stub(Object)

例如:

 when(mock.someMethod()).thenReturn(10);

 //you can use flexible argument matchers, e.g:
 //你可以使用靈活的參數匹配,例如 
 when(mock.someMethod(anyString())).thenReturn(10);

 //setting exception to be thrown:
 //設置拋出的異常
 when(mock.someMethod("some arg")).thenThrow(new RuntimeException());

 //you can set different behavior for consecutive method calls.
 //你可以對不同作用的連續回調的方法打測試樁:
 //Last stubbing (e.g: thenReturn("foo")) determines the behavior of further consecutive calls.
 //最後面的測試樁(例如:返回一個對象:"foo")決定了接下來的回調方法以及它的行爲。
 
 when(mock.someMethod("some arg"))
  .thenThrow(new RuntimeException())
  .thenReturn("foo");

 //Alternative, shorter version for consecutive stubbing:
 //可以用以下方式替代,比較小版本的連貫測試樁:
 when(mock.someMethod("some arg"))
  .thenReturn("one", "two");
 //is the same as:
 //和下面的方式效果是一樣的
 when(mock.someMethod("some arg"))
  .thenReturn("one")
  .thenReturn("two");

 //shorter version for consecutive method calls throwing exceptions:
 //比較小版本的連貫測試樁並且拋出異常:
 when(mock.someMethod("some arg"))
  .thenThrow(new RuntimeException(), new NullPointerException();

當你打空方法的測試樁,相關異常可參見:doThrow(Throwable),Stubbing可以被重寫:比如:普通的測試樁可以使用固定的設置,但是測試方法能夠重寫它。切記重寫測試樁是一種非常不推薦的寫法,因爲這樣做會導致非常多的測試樁。

一旦這個方法打過樁,無論這個方法被調用多少次,這個方法會一直返回這個測試樁的值。

當你對相同的方法調用相同的參數打測試樁很多次,最後面的測試樁則非常重要

儘管我們可以去驗證對測試樁的調用,但通常它都是多餘的。比如說你對foo.bar()打測試樁。如果你比較關心的是當某些情況foo.bar()中斷了(經常在verify()方法執行之前),此時會返回什麼。如果你的代碼不關心是get(0)會返回什麼那麼它就不應該被添加測試樁。如果你還不確定?看這裏

具體例子可以參考Javadoc中的Mockito

Parameters:

  • methodCall - 調用的方法

Returns:

  • 通常是OngoingStubbing對象。不要爲被返回的對象創建一個引用。

withSettings()函數

public static MockSettings withSettings()

可以在創建mock時添加設置。
不要經常去設置它。應該在使用簡單的mocks時寫簡單的設置。跟着我重複:簡單的測試會使整體的代碼更簡單,更可讀、更可維護。如果你不能把測試寫的很簡單-那麼請在測試時重構你的代碼。

mock設置的例子

   //Creates mock with different default answer & name
   //用不同的默認結果和名字去創建`mock`
   
   Foo mock = mock(Foo.class, withSettings()
       .defaultAnswer(RETURNS_SMART_NULLS)
       .name("cool mockie"));

   //Creates mock with different default answer, descriptive name and extra interfaces
   ////用不同的默認結果和描述的名稱以及額外的接口去創建`mock`
   Foo mock = mock(Foo.class, withSettings()
       .defaultAnswer(RETURNS_SMART_NULLS)
       .name("cool mockie")
       .extraInterfaces(Bar.class));

有兩種原因推薦使用MockSettings.第一種,有需求要增加另外一種mock設置,這樣用起來更方便。第二種,能夠結合不同的moke設置以減少大量重載moke()方法。

具體可參考MockSettings文檔來學習mock settins

Returns:

  • mock settings默認實例
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章