2011-11-25 44 views
17
的Mockito操縱

參數我有以下情況:磕碰方法與

class Worker { 
    public Integer somework() { 
     Integer k=0; 
     Helper h= new Helper(); 
     h.change(k); 
     return k; 
    } 
} 

class Helper { 
    public void change(Integer k) { 
    //k = Some calcs 
    } 
} 

我正在unitests爲Worker,顯然我需要模擬Helper類,這樣他change方法將總是把1到k

我的真實情況比較複雜,但是這段代碼代表了這個問題。感謝幫助。

回答

2

我會更改方法簽名並使其以Helper實例爲參數。調用者將創建幫助程序並將其傳遞給somework方法。測試會通過一個模擬幫手。

如果這是不可能的,至少調用一個受保護的工廠方法來創建的幫手,並且嘲笑這個工廠方法測試somework方法,以使其返回模擬助手時:

class Worker { 
    public Integer somework(){ 
     Integer k=0; 
     Helper h= createHelper(); 
     h.change(k); 
     return k; 
    } 

    // this method may be mocked when testing somework, to return a mock helper. 
    protected Helper createHelper() { 
     return new Helper(); 
    } 
} 
+1

恩..好的,那是一個選項。但是如果我無法更改當前的代碼,或者重構真實設計以便使測試更容易創建,那該怎麼辦? – TryHarder

+1

是的,沒錯。編寫可測試代碼是開發人員良好工作的重要組成部分。這就是IOC框架如此受歡迎的原因:它促進了一個使代碼可測試的設計。 –

+0

謝謝。我會離開這個線程,也許還有一些選項可以讓我用mockito來做什麼,只是爲了學習目的。同時我會遵循你的建議。 – TryHarder

4

對於@JB Nizet而言,是的,對可測試性進行重構是很好的。經常重構使代碼更具可測試性,會導致代碼更適合其他原因 - 關注點分離等。這並不總是可行的。說這不是你的代碼,或者你有其他的要求,讓它獨立(因爲很多其他類依賴於它的方式)或任何其他類。

如果我知道你需要做什麼,我想你可以用間諜做到這一點:

Worker workerUnderTest = new Worker(); 
Worker spiedWorkerUT = spy(workerUnderTest); 
Helper mockHelper = mock(Helper.class); 
when(spiedWorkerUT.createHelper()).thenReturn(mockHelper); 
Integer actual = spiedWorkerUT.someWork(); 
verify(mockHelper).change(0); 

然後使用spiedWorkerUT代替workerUnderTest的運行測試。

並不總是可以避免實例化你想要模擬的東西。爲此,有PowerMock

Helper mockHelper = mock(Helper.class); 
whenNew(Helper.class).withNoArguments().thenReturn(mockHelper); 
+0

感謝您的輸入。我實際上試圖做的是在'Worker'調用'change'方法時強制'mockHelper'改變他的行爲。從'Helper'繼承一些'mockHelper'並重寫'change'方法很容易實現,但是也許mockito可以在沒有新類的情況下幫助我? – TryHarder

+0

我很困惑。你想改變什麼? 「更改」是否會改變您傳遞的參數或更改其他呼叫的助手狀態? – jhericks

+0

它改變參數('k') – TryHarder

18

我有定義的方法是這樣的:

class Template{ 
    public void process(Object rootMap, StringWriter out){ 
....... 
    } 
} 

我會告訴你如何改變/修改 「OUT」(StringWriter的)參考。

private final Template mocktTemplate = mock(Template.class); 
doAnswer(new Answer<StringWriter>() { 

      public StringWriter answer(InvocationOnMock invocation) 
        throws Throwable { 
       Object[] args = invocation.getArguments(); 
       if (args[1] instanceof StringWriter) { 
        StringWriter stringWriter = (StringWriter) args[1]; 
        stringWriter.write("Email message"); 
       } 
       return null; 
      } 
     }).when(this.mocktTemplate).process(anyObject(),any(StringWriter.class)); 

現在,當你做出這樣的實際調用:

msgBodyTemplate.process(model, msgBodyWriter); 

在msgBodyWriter StringBuffer的參考價值將是「電子郵件信息」;不管它早先的價值。

+1

這太棒了! – devdanke

4

我認爲doAnswer是處理void方法的最好的方法,其中方法操作給定的參數。

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

基本上,獲取參數後,你可以做任何你想要的修改。有一個blog post解釋了一下。