Java 单元测试 - 如何使用模拟答案对异步方法(使用回调)进行单元测试

Bic*_*ick 5 java unit-testing callback mockito

我在类逻辑中有以下方法

public class Logic implements ILogic {

@Override
public void doSomethingInterestingAsync(final int number, 
                                        final ICallback callback){
    new Thread(new Runnable() {
        @Override
        public void run() {
            callback.response(number+1);
        }
    }).start();
  }
}
Run Code Online (Sandbox Code Playgroud)

我通常用

ILogic.doSomethingInterestingAsync(1, new ICallback() {
    @Override
    public void response(int number) {
        System.out.println(String.format("response - %s", number));
    }
});
Run Code Online (Sandbox Code Playgroud)

现在我想对它进行单元测试。

所以我想一个解决方案是使用CountDownLatch(在其他SO 线程中找到)
如下:

@Test
public void testDoSomethingInterestingAsync_CountDownLatch() throws Exception {
    final CountDownLatch lock = new CountDownLatch(1);

    ILogic ILogic = new Logic();
    final int testNumber = 1;
    ILogic.doSomethingInterestingAsync(testNumber, new ICallback() {
        @Override
        public void response(int number) {
            assertEquals(testNumber + 1, number);
            lock.countDown();
        }
    });
    assertEquals(true, lock.await(10000, TimeUnit.MILLISECONDS));
}
Run Code Online (Sandbox Code Playgroud)

而且效果很好。
但我也读过关于 Mockito 中的回答可能是更好的做法,
但我不能完全遵循这些例子。
如何使用 Mockito 工具使用回调为方法编写单元测试?
谢谢。

eth*_*far 3

我不明白为什么你需要CountDownLatch开始(根据你发布的代码判断),所以我将在我的答案中跳过它,请随意添加评论来解释我所缺少的内容。

我会按如下方式测试它:

@Test
public void testDoSomethingInterestingAsyncIncrementsParameter() {
    ILogic logic = new Logic();
    ICallback callback = mock(ICallback.class);

    logic.doSomethingInterestingAsync(SOME_NUMBER, callback);

    verify(callback, timeout(1000)).response(SOME_NUMBER + 1);
}
Run Code Online (Sandbox Code Playgroud)

  • 你当然是对的,但我不确定使用模拟是否可以得到相同的效果,这是你最初的问题。如果您愿意避免模拟,那么您的解决方案就很好。但需要注意的一件事是,您的解决方案处于单元测试的灰色区域,将其称为集成测试可能更合适。事实上,您正在使用锁运行真正的多线程测试,就单元测试而言,这有点牵强。但这是个人品味和偏好的问题。 (2认同)