如何使用CountdownLatch对异步代码进行单元测试同步

问题描述 投票:0回答:1

下面是我要测试的类: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()中测试逻辑?

java unit-testing service callback
1个回答
0
投票

我通过代码修改了公开我使用包保护函数注册的回调,如下所示:

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);
© www.soinside.com 2019 - 2024. All rights reserved.