在JavaScript中(例如使用Mocha),我可以编写异步单元测试,在最终回调中Assert内容。
这是通过将一个标记函数(通常称为done
)作为参数传递给测试方法来实现的。
当函数被调用时,测试框架知道测试已经完成。
例如:
it('succeeds or fails in the last callback', function(done) {
var deferred = Q.defer();
setTimeout(function() { deferred.resolve('expected'); }, 500);
deferred.promise.then(function(result) {
assertEquals('expected', result);
done(); // end of test
});
});
我发现Junit并不适合这样的场景。首先,测试方法不能处理参数,无论如何,如果我尝试例如:
@Test
public void testAssertionInsideContinuation() {
Long now = System.currentTimeMillis();
System.out.println("TimeMillis=" + now);
CompletableFuture fut = new CompletableFuture();
Executors.newScheduledThreadPool(1)
.schedule(() -> { fut.complete("whatever"); }, 500, TimeUnit.MILLISECONDS);
fut.thenRun(() -> {
long then = System.currentTimeMillis();
System.out.println("TimeMillis=" + then);
assertTrue(then - now >= 500);
});
}
第二个println
将不被执行,因为测试在很久以前已经愉快地完成了。
如果我作弊并在测试方法的末尾放置一个Thread.currentThread().sleep(500);
,那么未来就有机会完成,并执行Assert+第二个打印输出。
我有几个问题:
- 什么是最简单的Java设置,我可以在其中验证回调/延续/thenables(您可以随意调用它们)中的Assert,而不必阻塞测试?
- 我必须完全给予Junit吗?
- 是否有一个主流的测试框架(TestNG,也许?2)允许用这种方式编写异步单元测试?
顺便说一句,如果有人能建议我一种不用ScheduledFuture
来编写这个Java示例测试的方法,我也会很感激。我已经用supplyAsync
做了一些实验,但没有真正确定解决方案。
2条答案
按热度按时间r7knjye21#
当测试
CompletableFuture
时,您需要等到所有步骤都完成。添加最终
fut.join()
,而不是Thread.sleep
sulc1iza2#
JS测试的异步特性是一个使测试复杂化的问题(我们的大脑以同步的方式思考)。但是每个人(好吧,not everyone)都能接受它,因为这是NodeJS的特性,而不按照设计的方式使用这个工具可能是不明智的。
Java没有这个“问题”(你必须显式地选择使用NIO & Co来进行异步),这意味着你可以用正常(同步)的方式编写测试。因此,与其在不适合这种方式的环境中应用JS模式,不如用Java方式(或Rub-way,或.Net-way,或AlmostAnything-way)编写测试,而不用担心回调。
但是,如果您碰巧要测试异步代码(例如,您使用JMS之类的MOM),那么您可能需要查看Awaitility-用于测试此类情况的特殊库。