Mockito проверить не удалось во втором модульном тесте - PullRequest
0 голосов
/ 31 мая 2019

Я использую 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.

1 Ответ

1 голос
/ 31 мая 2019

Я думаю, что проблема многопоточная. Когда вы звоните initConnection, он вызывает mConnection.connect() в Thread Проблема, с которой вы сталкиваетесь, заключается в том, что для завершения этого Thread требуется некоторое время, и в итоге вы звоните verify(mockedZConnection, times(1)).connect(); до того, как поток действительно достигнет вызова connect(). Чтобы убедиться в этом, нужно присоединиться к Thread после его запуска, дождаться окончания действия Thread и продолжить:

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

}

Теперь оба теста должны работать.

Это, конечно, неприемлемо в коде, потому что оно отрицает использование Thread. Вам понадобится другой способ проверить это.

Я могу придумать способ дождаться завершения 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();
}

Попробовал и у меня работает нормально. Не уверен, что это лучшая практика, так как вам нужно обнародовать некоторые внутренности вашего класса, что нарушает инкапсуляцию

возможно, использование защищенного пакета isThreadAlive() в вашем классе ZConnectionService может быть приемлемым

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

и петля в тесте

while(zConnectionService.isThreadAlive()) {
    Thread.sleep(100);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...