2016-03-02 51 views
0

錯誤的Mockito我有一個Java類:定製匹配

import java.util.List; 
    public class Service 
    { 
    public List<Object> someMethod(final List<Object> list) { 
     return null; 
    } 
    } 

而且在那裏我已經定義了自定義匹配一個斯波克測試:

進口org.mockito.ArgumentMatcher 進口spock.lang。規格

import static org.mockito.Mockito.* 

    class InstantBookingInitialDecisionTest extends Specification { 

     def mock = mock(Service.class) 

     def setup() { 
      when(mock.someMethod(argThat(hasSize(2)))).thenReturn([]) 
      when(mock.someMethod(argThat(hasSize(3)))).thenReturn([]) 
     } 

     def 'Minimum hunger requirements do not apply to schedulable pros'() { 
      when: 
      'something' 
      then: 
      'something else' 
     } 

     // Damn, there's a Hamcrest matcher for this, but it's not in the jar that the javadocs say it is, so making my own 
     static def hasSize(size) { 
      new ArgumentMatcher<List>() { 
       @Override 
       boolean matches(Object o) { 
        List list = (List) o 
        return list.size() == size 
       } 
      } 
     } 
    } 

原樣,這個測試使我有以下錯誤:

java.lang.NullPointerException: Cannot invoke method size() on null object 

如果我刪除when中的任何一個,我就不會有任何錯誤。所以它不喜歡的是測試的殘段,以及我使用了自定義匹配器兩次的事實。

注:

  1. 我試圖聲明爲每個列表大小一個單獨的類,如mockito anyList of a given size和文檔的Mockito。我犯了同樣的錯誤。
  2. 我試過使用看起來像這樣的Hamcrest匹配器,但儘管1.3 Javadoc列出了一個Matchers.hasSize()方法,但我的導入的1.3 jar不包含匹配器。 (但即使我得到了依賴解決,我仍然想要了解問題。)

請不要問爲什麼我使用Mockito而不是Spock Mocks - 我有我的理由。 ;)

謝謝

+0

如果matches()檢查null併爲null參數返回false(因爲它應該這樣做,IMO)會發生什麼 –

+0

我正在使用Mockito文檔(基本上)的示例,它不檢查null。 – orbfish

回答

0

的根本原因是,您的自定義匹配可以拋出異常,這不符合匹配器的總承包。由於Mockito的內部原因,你在when中遇到它。

匹配器的合同指出matches(Object)可以接受任何對象並返回true或false。這意味着在每一個匹配器實現,你都不應該假設傳入的對象的類型,或者對象是否爲非空;畢竟,isNull()是一個完全有效和有用的匹配器。如果您希望匹配器爲任何空或非列表參數返回false,則應該手動檢查該匹配項,或者擴展TypeSafeMatcher<List>而不是BaseMatcher,以便在這些情況下Hamcrest可以返回false。否則,你冒着未被捕獲的ClassCastException或NullPointerException,這就是你在這裏得到的。這是唯一真正的問題,修復它將解決您的麻煩。


這是一個好時機,不過,來解釋的Mockito的語法。第一條線沒有問題,那麼爲什麼第二條線會失敗?答案是,當你的第二個行運行:

when(mock.someMethod(argThat(hasSize(3)))).thenReturn([]) 

...那麼Java評估呼叫when,所以它運行:

 mock.someMethod(argThat(hasSize(3))) 

...然後when可以檢測someMethod作爲最後調用的方法並開始其存根。與所有其他Mockito匹配器一樣,argThat的調用返回null(保留其副作用,Mockito可以分析Java何時調用when),但someMethod必須具有返回值,Mockito無法檢測到您是關於致電when。這意味着檢查現有的存根,因此它將nullargThat管入您的匹配器中,以查看它是否應用您的第一個存根,這會導致NullPointerException。 (我放多一點關於argThat的返回值和another SO answer的Mockito的評估順序。)

你無論如何要修理你的匹配器,但它也可以讓你有改寫第二行,如下所示:

doReturn([]).when(mock).someMethod(argThat(hasSize(3))) 

...因爲someMethod之前調用when意味着可以的Mockito暫時解除您的存根。只要第一行不會拋出異常或調用實際的實現,但將語法保留爲when並沒有什麼壞處,而Mockito會優雅地處理驗證。