簡體   English   中英

在帶有PowerMocktio的Java中,如何在私有嵌套類中實例化該類的構造函數?

[英]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);
    }
}

我懷疑您將不得不修改正在測試的代碼。 您有兩種選擇:

  1. 編寫涵蓋此代碼的大型集成測試,以便您擁有一個安全網 ,以防萬一您的更改可能破壞某些東西。 該測試可能會創建一個內存數據庫/后端,並使連接器連接到該數據庫/后端。
  2. 進行小而安全的更改 ,以創建測試接縫

最好同時做兩個。 有關更多詳細信息,請參見《 有效處理舊版代碼 》一書。

我將顯示一個選項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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM