Как выполнить модульное тестирование асинхронного кода, сделанного синхронным, с помощью CountdownLatch - PullRequest
0 голосов
/ 14 марта 2019

Ниже приведен класс, который я хочу проверить: SomeClass.java

public void SomeClass {

    final CountDownLatch latch = new CountDownLatch(1);
    int result;
    registerCallbackWithService(new MyCallback());

    public int callToExternalService(){
        //Do some stuff and make service call
        latch.await();
        return result;
    }

    class MyCallback implements ServiceCallback {
        @Override
        public void onResult(final int res) {
            //do something
            result = res;
            latch.countdown();
        }
    }
}

Обратный вызов MyCallback был зарегистрирован ранее до вызова callToExternalService().
Если я напишупростой тест, позволяющий просто смоделировать служебный вызов, сделанный в callToExternalService(), тест продолжает работать бесконечно из-за latch.await().
Как я могу проверить логику в callToExternalService(), а также в onResult()?

1 Ответ

0 голосов
/ 16 марта 2019

Я изменил по коду, чтобы показать обратный вызов, который я регистрирую, используя функцию с защитой пакета, как показано ниже:

public void SomeClass {

    private final CountDownLatch latch = new CountDownLatch(1);
    private int result;
    registerCallback(new MyCallback());

    public int callToExternalService(){
        //Do some stuff and make service call
        latch.await();
        return result;
    }

    private class MyCallback implements ServiceCallback {
        @Override
        public void onResult(final int res) {
            //do something
            result = res;
            latch.countdown();
        }
    }

    protected registerCallback(ServiceCallback callback) {
        registerCallbackWithService(callback);
    }
}

Теперь для тестирования я провожу тестирование, создав новый класс SomeClassTest extends SomeClass, и выполняю тестирование с использованием экземпляра этого класса. В SomeClassTest все, что я делаю, это перезаписываю registerCallback() для доступа к регистрируемому экземпляру обратного вызова.

public class ServiceTest {
    private ServiceCallback mServiceCallback;
    class SomeClassTest extends SomeClass {
        @Override
        registerCallback(ServiceCallback callback) {
            mServiceCallback = callback;
            super.registerCallback(callback);
        }
    }
}

Теперь все, что мне нужно сделать, используя doAnswer, вызывать обратный вызов по запросу на обслуживание, что приводит к выполнению latch.countdown() для той же ссылки latch, которая ставится на await сразу после выполнения запроса на обслуживание .

SomeClassTest someClassInstance = new SomeClassTest();
doAnswer(new Answer() {
            @Override
            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                mServiceVCallback.onResult(int_I_want_to_test_for)
                return null;
            }
        }).when(someClassInstance).service_request_before_latch_await();
int response = someClassInstance.callToExternalService();
assertEquals(response, expected_response);
...