Как выполнить модульное тестирование асинхронного кода, сделанного синхронным с помощью CountDownLatch

#java #unit-testing #service #callback

#java #модульное тестирование #Обслуживание #обратный вызов

Вопрос:

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

 public void SomeClass {

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

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

    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:

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

 public void SomeClass {

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

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

    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);