2012-01-25 66 views
8

我想模擬一些基於反射的方法。下面你可以看到細節,嘲笑基於調用的反射

類在測試

public class TracerLog { 
    @AroundInvoke 
    public Object logCall(InvocationContext context) throws Exception { 
     Logger logger = new Logger(); 
     String message = "INFO: Invoking method - " 
       + context.getMethod().getName() + "() of Class - " 
       + context.getMethod().getDeclaringClass(); 

     logger.write(message); 
     return context.proceed(); 
    } 
} 

測試

public class TracerLogTest { 

@Mock 
InvocationContext mockContext; 
@Mock 
Logger mockLogger; 
@InjectMocks 
private TracerLog cut = new TracerLog(); 

@BeforeMethod 
public void setup() { 
    MockitoAnnotations.initMocks(this); 
} 

@Test 
public void logCallTest() throws Exception { 
    when(mockContext.proceed()).thenReturn(true); 
    when(mockContext.getMethod().getDeclaringClass().getName()).thenReturn("someClass"); 
    cut.logCall(mockContext); 
    verify(mockContext).proceed(); 
} 

}

@Test 
public void logCallTest() throws Exception { 
    when(mockContext.proceed()).thenReturn(true); 
    when(mockContext.getMethod().getName()).thenReturn("someMethod"); 
    when(mockContext.getMethod().getDeclaringClass().getName()).thenReturn("someClass"); 
    cut.logCall(mockContext); 
    verify(mockLogger).write(anyString()); 
    verify(mockContext).proceed(); 
} 

但是,測試失敗,一個NullPointerException 。我明白我對嘲笑概念做錯了什麼,但我不明白它是什麼。您能否介紹一下,並告訴我該如何測試這種方法?

謝謝。

+0

你是如何創建你的模擬對象和你的對象在測試?你能發佈你的整個測試課程,而不僅僅是測試方法嗎?謝謝。 –

+0

@DavidWallace我現在編輯了問題以包含完整的代碼。 – Bala

回答

17

您需要一個Method對象和一個Class對象。根據你的評論,Mockito不能嘲笑一種方法,所以你需要一個真正的方法。我沒有測試過這個,但我相信這會起作用。相反的:

when(mockContext.getMethod().getName()).thenReturn("someMethod"); 
when(mockContext.getMethod().getDeclaringClass().getName()).thenReturn("someClass"); 

您需要:

// any method will do, but here is an example of how to get one. 
Method testMethod = this.getClass().getMethod("logCallTest"); 

when(mockContext.getMethod()).thenReturn(testMethod); 

顯然,getName()不會返回「的someMethod」了,並getDeclaringClass().getName()將返回該測試類的名稱(在本例中),不過雖然安:我不會選擇他們回來的東西,他們返回的東西仍然是確定性的,所以你應該能夠驗證你需要的任何東西。 (當然,如果你需要間諜或者驗證一個調用是在Method對象上進行的,你仍然會被卡住。)

+0

感謝您的回答,但Mockito抱怨​​說它無法模擬或窺探java.lang.reflect.Method。還有其他方法可以實現嗎? – Bala

+0

我編輯了我的答案以顯示如何使用真實的Method對象。這應該解決您的問題中的簡單示例,但仍然存在限制。 – jhericks

+0

感謝您的建議,但mockContext.getMethod()。getDeclaringClass()在這種情況下不起作用。 – Bala

3

是的問題是mockContext.getMethod()將返回null。所以每次你運行這個,然後調用結果(getDeclaringClass()或getName()),你會得到NPE。當您設置模擬時,您可能需要使用RETURNS_DEEP_STUBS默認答案。像

@Mock(answer = RETURNS_DEEP_STUBS) private InvocationContext mockContext; 

應該做的伎倆。

+0

嗨大衛我主要同意你的看法。但對於讀者來說:Method是一個最終的類,它不能被Mockito嘲笑;)我也不推薦模擬你不擁有的類型。 – Brice

+0

哦,麻煩了。布萊斯是對的(他通常是關於這些事情的)。由於Mockito不能嘲笑最終課程,所以我沒有辦法做到原來的海報想要的。抱歉。 –

+0

@Brice好吧,我同意你的看法,但是InvocationContext不是最終的類,因爲我不希望應用程序服務器運行在我的測試中。我在某個地方出了問題嗎? – Bala