簡體   English   中英

Mockito驗證在第二個單元測試中失敗

[英]Mockito verify fails in second unit test

我將Mockito與JUnit一起使用以實現Android項目中某個類的單元測試。問題是我在兩個隨后的測試中調用Mockito.verify ,它們的測試完全相同(以確保我正確使用了Mockito),但是有趣的是,第二個測試中的驗證總是會失敗。我懷疑在每次測試之前都需要使用@before注釋或類似的東西進行一些操作,但我錯過了,這里有一些我正在做的代碼片段。

我使用Android Studio 3.4.1,Mockito 2.7.22和JUnit 4.12。

@Test
public void test_onStart_do_nothing() throws Exception {
    ZConnectionService zConnectionService = new ZConnectionService();
    ZConnection mockedZConnection = mock(ZConnection.class);

    doNothing().when(mockedZConnection).connect();
    zConnectionService.initConnection(mockedZConnection);

    verify(mockedZConnection, times(1)).connect();
}

@Test
public void test_onStart_throw_IO_exceptioon() throws Exception {
    ZConnectionService zConnectionService = new ZConnectionService();
    ZConnection mockedZConnection = mock(ZConnection.class);

    doNothing().when(mockedZConnection).connect();
    zConnectionService.initConnection(mockedZConnection);
    // Line above is the line that error message points to!

    verify(mockedZConnection, times(1)).connect();
}

測試功能到了

public void initConnection(ZConnection connection) {
    Log.d(TAG,"initConnection()");

    if (mConnection == null) {
        mConnection = connection;
    }

    if (!mActive) {
        mActive = true;

        if (mThread == null || !mThread.isAlive()) {
            mThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    // The code here runs in a background thread.
                    Looper.prepare();
                    mTHandler = new Handler();

                    try {
                        mConnection.connect();
                    } catch (IOException e) {
                        Intent i = null;
                        i = new Intent(ZConnectionService.UI_NOTCONNECTED);
                        i.setPackage(getApplicationContext().getPackageName());
                        getApplicationContext().sendBroadcast(i);

                        e.printStackTrace();

                        // Stop the services all together.
                        stopSelf();
                    }

                    Looper.loop();
                }
            });

            mThread.start();
        }
    }
}

我希望兩項測試都可以順利通過。 實際上,當我分別運行它們時,兩個測試都通過了,但是當我運行整個套件時它們都失敗了,錯誤是:

Wanted but not invoked:
mockedZinkConnection.connect();
-> at com.app.z.ZConnectionServiceUnitTest.test_onStart_throw_IO_exceptioon(ZConnectionServiceUnitTest.java:207)
Actually, there were zero interactions with this mock.

我認為這個問題是多線程的。 當您調用initConnection ,它將在Thread調用mConnection.connect() 。您遇到的問題是該Thread需要一些時間才能完成,最終您會調用verify(mockedZConnection, times(1)).connect(); 在線程實際到達connect()調用之前。 確保它的一種方法是在啟動Thread后將其加入,它將等待Thread完成后再繼續:

mThread.start();
try {
    mThread.join();
} catch (InterruptedException i) {
    i.printStackTrace();

}

現在,這兩個測試都應該起作用。

當然這在代碼中是不可接受的,因為它否定了Thread的使用。 您將需要其他方式進行測試。

我能想到的一種方法是在測試模擬之前等待線程完成測試:

@Test
public void test_onStart_throw_IO_exceptioon() throws Exception {
    ZConnectionService zConnectionService = new ZConnectionService();
    ZConnection mockedZConnection = mock(ZConnection.class);
    doNothing().when(mockedZConnection).connect();

    zConnectionService.initConnection(mockedZConnection);

    // Wait for the Thread to complete
    while(zConnectionService.mThread.isAlive()) {
        Thread.sleep(100);
    }
    verify(mockedZConnection, times(1)).connect();
}

嘗試過,對我來說很好。 但不確定是否是最佳做法,因為您需要公開類的某些內部信息,這違反了封裝

也許在您的ZConnectionService類上使用受保護的包isThreadAlive()方法是可以接受的

boolean isThreadAlive() {
    return mThread.isAlive();
}

和測試中的循環

while(zConnectionService.isThreadAlive()) {
    Thread.sleep(100);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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