You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vert.x 3.8.1单元测试出现TimeoutException问题咨询

Vert.x 3.8.1 单元测试TimeoutException 问题排查与解决

嘿,我之前也踩过这个Vert.x单元测试的坑!你明明在代码里加了completeNow(),也没有阻塞操作,结果还是触发了超时,确实挺让人困惑的。让我帮你分析下问题,再给出几个解决办法。

你的代码与报错信息

TestMainVerticle.java

@ExtendWith(VertxExtension.class)
public class TestMainVerticle {
    @BeforeEach
    void deploy_verticle(Vertx vertx, VertxTestContext testContext) {
        vertx.deployVerticle(new MainVerticle(), testContext.succeeding(id -> testContext.completeNow()));
    }

    @Test
    void verticle_deployed(Vertx vertx, VertxTestContext testContext) throws Throwable {
        testContext.completeNow();
    }
}

MainVerticle.java

public class MainVerticle extends AbstractVerticle {
    @Override
    public void start(Promise<Void> startPromise) throws Exception {
    }
}

报错输出

测试执行超时。请确保您的异步代码包含对VertxTestContext#completeNow()、VertxTestContext#failNow()或Checkpoint#flag()的调用。

java.util.concurrent.TimeoutException: 测试执行超时。请确保您的异步代码包含对VertxTestContext#completeNow()、VertxTestContext#failNow()或Checkpoint#flag()的调用
    at io.vertx.junit5.VertxExtension.joinActiveTestContexts(VertxExtension.java:230)
    at io.vertx.junit5.VertxExtension.beforeTestExecution(VertxExtension.java:191)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeTestExecutionCallbacks$5(TestMethodTestDescriptor.java:155)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:169)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeTestExecutionCallbacks(TestMethodTestDescriptor.java:154)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:125)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    ...

问题根源

问题出在你的@BeforeEach方法里的部署逻辑!因为你的MainVerticle的start方法是同步完成的(空实现,直接就完成了Promise),导致vertx.deployVerticle的成功回调是在当前线程同步执行的——这时候VertxTestContext还没完全初始化好,你提前调用了completeNow(),会让测试上下文的状态出现异常,后续测试执行时就会误以为没有正确标记完成,从而触发超时。

解决办法

1. 使用Checkpoint替代直接调用completeNow()

这是最稳妥的方案,Checkpoint是Vert.x JUnit5扩展专门设计用来同步测试状态的工具,能避免同步回调导致的上下文问题:

@BeforeEach
void deploy_verticle(Vertx vertx, VertxTestContext testContext) {
    // 创建一个检查点
    Checkpoint deploymentCheckpoint = testContext.checkpoint();
    vertx.deployVerticle(new MainVerticle(), testContext.succeeding(id -> {
        // 标记检查点完成
        deploymentCheckpoint.flag();
    }));
}

2. 让MainVerticle的start方法异步完成

如果你的业务逻辑本来就是异步的,或者可以模拟异步操作,让start方法通过Vert.x的事件循环来完成Promise,就能避免同步回调的问题:

@Override
public void start(Promise<Void> startPromise) throws Exception {
    // 用一个1ms的定时器模拟异步初始化
    vertx.setTimer(1, id -> startPromise.complete());
}

3. 升级Vert.x版本到3.8.5及以上

这个问题在Vert.x 3.8.5的小版本更新里被官方修复了,他们针对同步Verticle部署的测试场景做了优化。如果你的项目允许升级版本,这是最省心的解决方案。

验证

按照上面的任意一种方法修改后,再运行单元测试,应该就能正常通过,不会再出现TimeoutException了!

内容的提问来源于stack exchange,提问作者Jingwei Li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:22:40