Mockito--完整功能介紹(轉)


 

public interface DBAccess {
    int delete(String moi,String moc) throws Exception;
    void create(String moi,String moc,Map<String,Object> attributes)throws Exception;
    List<Map<String, Object>> select(String moi,String moc,String[] attributes) throws Exception;
    int update(String moi,String moc,Map<String,Object> attributes)throws Exception;
}

Mock:

        dbAccess=mock(DBAccess.class);
        Collection<String> attrs=anyCollectionOf(String.class);
        when(dbAccess.select(anyString(), anyString(),attrs.toArray(new String[attrs.size()]) )).thenReturn(resultList);



            verify(dbAccess,times(wantedNumberOfInvocations)).create(anyString(), anyString(), anyMapOf(String.class, Object.class));

 

 

回到官網:http://mockito.org/,打開documentation可以看到原文。

強烈建議不熟悉Mockito的同學先看看我寫的Mockito(一)入門篇和(二)實例篇之后再來看這篇文章。

因為只有看了前兩篇文章才明白mockito的本質以及該如何使用它。

下面是按原文 翻譯+注釋 的對Mockito全部功能的介紹。

 

1, 使用mockito驗證行為。

//首先要importMockito.

import static org.mockito.Mockito.*;

//mock creation

List mockedList = mock(List.class);

//using mock object

mockedList.add("one");

mockedList.clear();

//驗證add方法是否在前面被調用了一次,且參數為“one”。clear方法同樣。

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

verify(mockedList).clear();

//下面的驗證會失敗。因為沒有調用過add("two")。

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

原文中的一句話很重要:Once created, mock will remember all interactions.所以mockito知道前面是否調用過某方法。

 

2, 使方法調用返回期望的值。也被稱為stubbing

//You can mock concrete classes, not only interfaces

LinkedList mockedList = mock(LinkedList.class);

//stubbing。當get(0)被調用時,返回"first". 方法get(1)被調用時,拋異常。

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));

默認情況下,對於所有有返回值且沒有stub過的方法,mockito會返回相應的默認值。

對於內置類型會返回默認值,如int會返回0,布爾值返回false。對於其他type會返回null。

這里一個重要概念就是: mock對象會覆蓋整個被mock的對象,因此沒有stub的方法只能返回默認值。

 

//重復stub兩次,則以第二次為准。如下將返回"second":

when(mockedList.get(0)).thenReturn("first");

when(mockedList.get(0)).thenReturn("second");

//如果是下面這種形式,則表示第一次調用時返回“first”,第二次調用時返回“second”。可以寫n多個。

when(mockedList.get(0)).thenReturn("first").thenReturn("second");

但是,如果實際調用的次數超過了stub過的次數,則會一直返回最后一次stub的值。

如上例,第三次調用get(0)時,則會返回"second".

 

3, 參數匹配

在上例中如果想實現get(任意整數)時,都返回“element”時,該怎么做呢?很簡單。

//stubbing 使用了內置的anyint() matcher.

when(mockedList.get(anyInt())).thenReturn("element");

//因此除了anyint()之外,還有其他很多matcher。這里請參考原文。

//使用了matcher一樣可以驗證被調用的次數。

verify(mockedList).get(anyInt());

這里有一個限制就是,如果在調用方法時需要傳入多個參數,其中一個參數使用了argument matcher,那么所有的參數必須都是matcher。

不可以matcher和實際的參數混着用。

 

這里也可以使用custom argument matcher。因為很多時候輸入參數不是build-in 類型,而是我們自己寫的一些類,或特殊對象。

這時要使用argument matcher,就必須訂制特殊的matcher了。

下例是一個特殊的matcher的實例,這個matcher可以匹配任何file對象。

public class SayHiTest {

 @Test
 public void testSayHi() throws Exception {
     File mock = mock(File.class); //首先mock File類。
     //注意new IsAnyFiles()並不是一個matcher,需要調用argThat(new IsAnyFiles()))才返回一個matcher。

     //下句中stub:當調用renameTo方法時,返回false。該方法參數可以是任意file對象。

     when(mock.renameTo(argThat(new IsAnyFiles()))).thenReturn(false); 
     mock.renameTo(new File("test")); 

     //下句verify renameTo方法被調用了一次,同時輸入參數是任意file。
     verify(mock).renameTo(argThat(new IsAnyFiles()));
 }
}
 
class IsAnyFiles extends ArgumentMatcher<File> {
    public boolean matches(Object file) {
        return file.getClass() == File.class;
    }
 }

另外一個參數匹配的例子:

 

            class IsSOAPMessage extends ArgumentMatcher<SOAPMessage> {

                        public boolean matches(Object soapMessage) {

                                    return (soapMessage instanceof SOAPMessage) || soapMessage==null;

                        }

            }

//上面的macther不僅可以匹配任意的SOAPMessage對象,如果輸入參數為空也可以匹配上。

這里說一下我犯過的一個錯誤。

我在做參數匹配的時候,沒有考慮到輸入參數為空的情況,導致matcher匹配不上,進而stub的行為無法生效。

其實在發現mock對象沒有想自己想象的方式工作時,最好的方法就是debug進去,首先要先確定mock對象是不是真的傳遞進去了。然后再一步步的debug。

通常遇到的兩種情況就是1,mock對象沒有傳遞進去。2,參數沒有匹配上。

 

 

4, 驗證方法被調用了特定次數/至少x次/最多x次/從未被調用

//是否add("twice")被調用了兩次。

 verify(mockedList, times(2)).add("twice");

//驗證add("twice")被調用了至少一次。以及其他。

verify(mockedList, atLeastOnce()).add("twice");

verify(mockedList, atLeast(2)).add("twice");

verify(mockedList, atMost(5)).add("twice");

verify(mockedList, never()).add("twice");

 

 

5, 調用方法時拋出異常

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

后面還會再介紹幾個類似的方法,例如doReturn()。

 

 

6, 驗證順序

//下面的代碼驗證firstMock先被調用,secondMock后被調用。

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

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

 

 

7, 驗證mock之間沒有相互作用6,7都不是很明白實際意義是什么。

 

 

8, 找到冗余的調用

用never()就可以實現,不多說

 

9, 使用@mock 定義mock。


之前都是使用mock()來模擬一個對象。用@mock是一個shorthand。

public class ArticleManagerTest {

@Mock private ArticleCalculator calculator;

@Mock private ArticleDatabase database;

@Mock private UserProvider userProvider;

private ArticleManager manager;

之后再繼續介紹mockito復雜一點的功能。

 

http://blog.csdn.net/onlyqi/article/details/6544989

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM