如何让测试等待Verticle完全部署后再执行?
Vert.x测试等待Verticle完全部署的解决方案
问题描述
我在为Vert.x API编写测试时遇到了问题:使用OpenAPI从api-curio schema registry下载的配置设置路由,应用本身运行正常,但部分测试无法正常工作,测试似乎在路由实际设置完成前就已执行。需要让测试等待Verticle完全部署后再执行。
问题代码
测试类中的@BeforeEach方法
@BeforeEach void deploy_verticle(Vertx vertx, VertxTestContext testContext) { mainVerticle = new MainVerticle(); client = vertx.createHttpClient(); ConfigStoreOptions propertyFile = new ConfigStoreOptions() .setType("file") .setFormat("properties") .setConfig(new JsonObject().put("path", "src/main/resources/local_config.properties")); ConfigRetrieverOptions options = new ConfigRetrieverOptions() .addStore(propertyFile); ConfigRetriever retriever = ConfigRetriever.create(vertx, options); retriever.getConfig(config -> vertx.deployVerticle(mainVerticle, new DeploymentOptions().setConfig(config.result()), testContext.succeedingThenComplete())); }
测试方法
@Test void listEmployeTest(Vertx vertx, VertxTestContext testContext) throws Throwable { HttpClient client = vertx.createHttpClient(); client.request(HttpMethod.GET, 8080, "localhost", "/v2.3/employes/").compose(request -> request.send()).onSuccess(body -> { assertEquals(200, body.statusCode()); testContext.completeNow(); }).onFailure(failure -> testContext.failNow(failure)); }
问题原因
Vert.x的vertx.deployVerticle方法默认只等待Verticle实例启动完成,不会等待Verticle内部的异步初始化逻辑(比如从schema registry下载配置、初始化路由等)执行完毕。如果你的MainVerticle的start方法里包含这些异步操作,测试会在这些操作完成前就开始执行,导致请求找不到路由或返回错误。
解决方案
1. 修改MainVerticle的start方法,用Promise控制部署完成时机
在MainVerticle的start方法中传入Promise<Void>,在所有异步初始化操作(下载schema、设置路由、启动HTTP服务器等)完成后调用promise.complete(),让Vert.x等待所有异步任务结束后再标记Verticle部署成功。
示例代码:
public class MainVerticle extends AbstractVerticle { @Override public void start(Promise<Void> startPromise) throws Exception { // 加载配置 ConfigRetriever retriever = ConfigRetriever.create(vertx); retriever.getConfig(configResult -> { if (configResult.failed()) { startPromise.fail(configResult.cause()); return; } JsonObject config = configResult.result(); // 异步下载OpenAPI schema vertx.createHttpClient() .request(HttpMethod.GET, config.getInteger("schema.port"), config.getString("schema.host"), config.getString("schema.path")) .compose(HttpClientRequest::send) .compose(HttpClientResponse::body) .onSuccess(schemaBody -> { // 基于schema初始化路由 Router router = Router.router(vertx); // 这里添加路由设置逻辑 // ... // 启动HTTP服务器 vertx.createHttpServer() .requestHandler(router) .listen(config.getInteger("http.port"), listenResult -> { if (listenResult.succeeded()) { // 所有异步操作完成,标记Verticle部署成功 startPromise.complete(); } else { startPromise.fail(listenResult.cause()); } }); }) .onFailure(startPromise::fail); }); } }
2. 保持测试类部署逻辑不变
原@BeforeEach方法无需修改,此时vertx.deployVerticle会等待MainVerticle的startPromise完成后才触发testContext.succeedingThenComplete(),确保测试在所有初始化操作完成后才执行。
额外优化建议
- 测试中复用同一个
HttpClient实例,避免每个测试方法重复创建,减少资源消耗。 - 在
@AfterEach方法中清理资源:
@AfterEach void tearDown(Vertx vertx, VertxTestContext testContext) { if (client != null) { client.close(); } vertx.undeploy(mainVerticle.deploymentID(), testContext.succeedingThenComplete()); }
内容的提问来源于stack exchange,提问作者Ikarus
相关产品推荐
相关产品推荐

