使用Jmockit验证FutureCallback效果的最佳方法

时间:2015-03-03 23:16:30

标签: java junit jmockit

验证Jmockit中回调效果的首选机制是什么?

例如,假设我有这门课。

class ResultGenerator {
    AsyncLauncher asyncLauncher = new AsyncLauncher();

    public void getResultAsync(final ResultSignal resultSignal) {
        asyncLauncher.getResult(new FutureCallback<Result>() {
                @Override
                public void onSuccess(@Nullable Result result) {
                    resultSignal.success(result);
                }

                @Override
                public void onFailure(Throwable t) {
                    resultSignal.failure();
                }
        });
    }
}

在为resultSignal.success(result)编写测试时,如何验证ResultGenerator#getResultAsync

2 个答案:

答案 0 :(得分:3)

例如

@RunWith(JMockit.class)
public class ResultGeneratorTest {
    // Synchronous invocation, mocked AsyncLauncher
    @Test
    public void testGetResultAsync(@Mocked final ResultSignal resultSignal, @Mocked final Result result) throws Exception {
        new MockUp<AsyncLauncher>() {
            @Mock
            void getResult(FutureCallback<Result> futureCallback) {
                futureCallback.onSuccess(result);
            }
        };
        ResultGenerator resultGenerator = new ResultGenerator();
        resultGenerator.getResultAsync(resultSignal);
        new Verifications() {{
            resultSignal.success((Result) any); times = 1;
            resultSignal.failure(); times = 0;
        }};
    }

    // Asynchronous invocation, real AsyncLauncher in use
    @Test
    public void testGetResultAsyncDelayed(@Mocked final Result result) throws Exception {
        final AtomicBoolean latch = new AtomicBoolean(false);
        MockUp<ResultSignal> resultSignalMockUp = new MockUp<ResultSignal>() {
            @Mock(invocations = 1)
            public void success(Result result) {
                latch.set(true);
            }

            @Mock(invocations = 0)
            public void failure() {
                latch.set(true);
            }
        };
        ResultGenerator resultGenerator = new ResultGenerator();
        final ResultSignal resultSignal = resultSignalMockUp.getMockInstance();
        resultGenerator.getResultAsync(resultSignal);
        Awaitility.await().untilTrue(latch);
    }

}

答案 1 :(得分:0)

几个笔记:

  1. ResultGenerator是您的SUT(受测试系统),您不应该模拟内部
  2. ResultSignal是测试合作者,因此很自然地将其嘲笑
  3. 因为你可以验证这样的功能,单元测试理论中唯一的“正确”解决方案就是模仿合作者
  4. 您必须确保正确处理超时,否则测试可能永远不会结束
  5. 所以一种可能的解决方案是:

    @Test
    public void getResultAsync_ShouldNotifyResultSignal() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);
    
        ResultGenerator generator = new ResultGenerator();
    
        generator.getResultAsync(new MyResultSignal(latch));
    
        assertTrue(latch.await(1, SECONDS));
    }
    
    private static final class MyResultSignal implements ResultSignal {
        private final CountDownLatch latch;
    
        private MyResultSignal(CountDownLatch latch) {
            this.latch = latch;
        }
    
        @Override
        public void success(Result result) {
            latch.countDown();
        }
    
        @Override
        public void failure() {}
    }