[英]In Java with PowerMocktio, how do you mock the constructor of a class when it's instantiated inside a private nested class?
我有一個包含要測試的幾種方法的類,以及在其中一些方法中使用的私有嵌套類。 在這個私有的嵌套類中,它創建一個對象,該對象試圖與網站或數據庫建立連接。 我想分開測試,以連接到該外部資源以及對檢索到的信息進行的處理。 這樣,我們可以選擇不將測試環境連接到功能“外部”源,從而大大簡化了這些測試所需的設置。
為此,我正在編寫一個測試,該測試模擬試圖建立這些連接的對象的構造函數。 當嵌套的私有類嘗試形成連接時,並且當它嘗試檢索信息時,我不希望它做任何事情,我希望它僅返回預定義的數據字符串。 目前,我有一些類似的東西:
public class MyClass {
public int mainMethod() {
//Some instructions...
NestedClass nestedClass = new NestedClass();
int finalResult = nestedClass.collectAndRefineData();
}
private class NestedClass {
public NestedClass() {
Connector connect = new Connector();
}
public int collectAndRefineData() {
//Connects to the outside resource, like a website or database
//Processes and refines data into a state I want
//Returns data
}
}
測試類如下所示:
@RunWith(PowerMockRunner.class)
@PrepareForTest({Connector.class})
public class MyClassTests {
@Test
public void testOne() {
mockConnector = mock(Connection.class);
PowerMockito.whenNew(Connector.class).withNoArguments().thenReturn(mockConnector);
MyClass testClass = new MyClass();
int result = testClass.mainMethod();
Assert.equals(result, 1);
}
}
現在,我確實知道 ,在PrepareForTest批注中,我需要包括實例化要為其模擬構造函數的對象的類。 問題是我不能放MyClass,因為那不是創建它的對象,我不能放NestedClass,因為它在測試中看不到。 我曾嘗試將MyClass.class.getDeclaredClasses [1]放入正確的類中,但是不幸的是PowerMocktio需要在注釋中添加一個常量,這根本行不通。
誰能想到一種使此模擬構造函數起作用的方法?
注意:我無法對正在測試的代碼進行任何更改。 這是因為該代碼目前可以正常工作,已經過手動測試,我正在編寫此代碼,以便將來的項目將使用此自動測試框架。
我不確定您是否正在運行與Mockito集成的測試,如果可以,則可以使用以下代碼:
@RunWith(PowerMockRunner.class)
@PrepareForTest({Connector.class})
public class MyClassTests {
@Mock
Connector mockConnector;
@InjectMocks
MyClass testClass;
@Test
public void testOne() {
PowerMockito.whenNew(Connector.class).withNoArguments().thenReturn(mockConnector);
int result = testClass.mainMethod();
Assert.equals(result, 1);
}
}
我懷疑您將不得不修改正在測試的代碼。 您有兩種選擇:
最好同時做兩個。 有關更多詳細信息,請參見《 有效處理舊版代碼 》一書。
我將顯示一個選項2的示例。
首先,您可以創建一個“ seam”,以使測試能夠更改Connector
的創建方式:
public class MyClass {
public int mainMethod() {
// Some instructions...
NestedClass nestedClass = new NestedClass();
return nestedClass.CollectAndRefineData();
}
// visible for testing
Connector createConnector() {
return new Connector();
}
private class NestedClass {
private final Connector connector;
public NestedClass() {
connector = createConnector();
}
...
}
}
然后,您可以使用MyClass
的部分模擬來測試您的代碼。
@RunWith(JUnit4.class)
public class MyClassTests {
@Test
public void testOne() {
MyClass testClass = spy(MyClass.class);
Connector mockConnector = mock(Connector.class);
when(testClass.createConnection())
.thenReturn(mockConnector);
int result = testClass.mainMethod();
Assert.assertEquals(1, result);
}
}
請注意, assertEquals
期望第一個參數為期望值。
另請注意,此測試使用Mockito而不是PowerMock 。 這樣做很好,因為使用PowerMock的測試可能會很脆弱,並且由於被測代碼的微小更改而容易損壞。 請注意,使用部分模擬也可能很脆弱。 我們會盡快解決。
通過測試后,您可以重構代碼,以便調用方通過Connector
工廠:
public class MyClass {
private final ConnectorFactory connectorFactory;
@Inject
MyClass(ConnectorFactory factory) {
this.connectorFactory = factory;
}
// visible for testing
Connector createConnector() {
return connectorFactory.create();
}
private class NestedClass {
private final Connector connector;
public NestedClass() {
connector = createConnector();
}
...
}
}
使用MyClass
的代碼最好使用依賴注入框架,例如Guice或Spring。 如果這不是一個選擇,則可以使第二個無參數構造函數傳入真實的ConnectorFactory
。
假設測試仍然通過,則可以通過將測試更改為模擬ConnectorFactory
而不是對MyClass
進行部分模擬來使測試不那么脆弱 。 當這些測試通過時,可以內聯createConnector()
。
將來,請嘗試在編寫代碼時編寫測試 (或至少在花費大量時間進行手動測試之前)。
mockConnector =模擬(Connection.class);
未聲明此對象。 無論如何,無論如何,您都必須使用@Mock注釋。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.