[英]How to mock an object created via Class.newInstance(className)?
我正在嘗試將單元測試添加到一些遺留代碼中,這些代碼具有傳遞給它的 String 類名,並創建一個使用Class.newInstance(String className)
實現特定處理程序接口的對象。 我可以控制我傳遞的類名,我可以獲得指向新處理程序對象的指針(通過getHandler()
調用),並且我想使用 Mockito 觀察對它的調用。
我目前的解決方案是:
TestHandler
。getMock()
方法使模擬對象可訪問。objectUnderTest.getHandler().getMock()
進行 verify() 調用來觀察對象。這有效,但感覺有點不雅,尤其是必須手動編寫所有傳遞方法。
有更好的解決方案嗎?
從根本上說,您遇到了與嘗試使用new
測試新創建的實例相同的問題; Class.newInstance
(可能正確Class.forName(foo).newInstance()
)不會傷害您,但也不會幫助您。
作為旁注,您的TestHandler
聽起來像是一個通用的委托實現,無論如何聽起來都非常有用(特別是如果您需要編寫 Handler 包裝器)。 如果是,您可能希望將其提升為與生產代碼樹中的 Handler 相鄰。
雖然我承認您提到了遺留代碼,但如果允許您重構以包含測試接縫,這將變得非常容易。 (為了便於解釋,這里忽略反射異常。)
public ReturnType yourMethodUnderTest(String className) {
return yourMethodUnderTest(Class.newInstance(className));
}
/** Package private for testing. */
public ReturnType yourMethodUnderTest(Handler handler) {
return yourMethodUnderTest(Class.newInstance(className));
}
您還可以提取對象創建並在測試中替換它:
/** Instance field, package-private to replace in tests. */
Function<String, Handler> instanceCreator =
( x -> (Handler) Class.forName(x).newInstance());
public ReturnType yourMethodUnderTest(String className) {
Handler handler = instanceCreator.apply(className);
// ...
}
你甚至可以把它提取到一個方法中並在你的測試中替換它:
public ReturnType yourMethodUnderTest(String className) {
Handler handler = createHandler(className);
// ...
}
/** Package private for testing. */
Handler createHandler(String className) {
return Class.forName(className).newInstance();
}
@Test public void yourTest() {
// Manually replace createHandler. You could also use a Mockito spy here.
ObjectUnderTest objectUnderTest = new ObjectUnderTest() {
@Override Handler createHandler(String className) {
return mock(Handler.class);
}
}
// ...
}
旁注:即使 Mockito 創建了一個命名的動態類型,您幾乎肯定無法破解它並允許您的代碼按名稱創建它。 這是因為對mock
的調用在 Mockito 的內部 state 中注冊了實例。
// BAD: Unlikely to work
@Test public void yourTest() {
objectUnderTest.methodUnderTest(
mock(Handler.class).getClass().getName());
// ...
}
創建一個公共方法,您將在其中放置獲取類的 newInstance 的邏輯
ClassA objectClassA=createNewInstance(className);
同樣,並且
public ClassA createInstance(String className){
return (ClassA) (Class.forName(className)).newInstance();
}
現在假設我們在 ClassB 的內部創建了一個 classA 的實例,然后在 B 的 TestClass 中,我們可以簡單地模擬這個 createInstance 方法
doReturn(mockClassA).when(mockClassB).createInstance(className);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.