MongoTemplate与Testcontainers测试:如何避免超时并立即抛出DataAccessException
解决MongoDB不可用场景测试的超时问题
要解决停止MongoDBContainer后测试等待30秒的问题,核心是调整MongoClient的超时参数,让客户端在连接失败时快速抛出异常,而非长时间等待。具体实现如下:
1. 自定义快速失败的MongoTemplate
创建配置了短超时参数的MongoTemplate,替换业务代码中默认的实例:
private MongoTemplate createFastFailingMongoTemplate(MongoDBContainer mongoDBContainer) { MongoClientSettings clientSettings = MongoClientSettings.builder() .applyConnectionString(new ConnectionString(mongoDBContainer.getReplicaSetUrl())) // 设置100ms连接超时,连不上直接报错 .applyToSocketSettings(builder -> builder.connectTimeout(Duration.ofMillis(100)) .readTimeout(Duration.ofMillis(100))) // 读取超时同样设为100ms // 100ms内找不到可用服务器就抛出异常 .applyToClusterSettings(builder -> builder.serverSelectionTimeout(Duration.ofMillis(100))) .build(); MongoClient fastFailingClient = MongoClients.create(clientSettings); return new MongoTemplate(fastFailingClient, "your-db-name"); }
2. 在测试中替换MongoTemplate
在测试方法内停止MongoDB容器后,将业务服务的MongoTemplate替换为快速失败版本:
@Test void savingDocumentToDbReturns503() throws Exception { // 停止容器模拟Mongo不可用状态 mongoDBContainer.stop(); // 替换业务服务中的MongoTemplate MongoTemplate fastFailingTemplate = createFastFailingMongoTemplate(mongoDBContainer); // 假设业务服务有setter方法注入MongoTemplate,也可通过反射修改 yourBusinessService.setMongoTemplate(fastFailingTemplate); // 执行请求,此时会快速触发DataAccessException,返回503 mockMvc.perform(post("/endpoint") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isServiceUnavailable()); // 测试完成后恢复容器和原MongoTemplate mongoDBContainer.start(); MongoTemplate originalTemplate = applicationContext.getBean(MongoTemplate.class); yourBusinessService.setMongoTemplate(originalTemplate); }
关键参数说明
connectTimeout:客户端尝试建立连接的最大等待时间,超时直接抛出连接异常readTimeout:读取MongoDB响应的最大等待时间,避免无意义等待serverSelectionTimeout:Mongo客户端选择可用服务器的超时时间,无可用节点时立刻抛出异常
可根据实际情况微调超时时间(比如设为200ms),平衡测试效率和误判风险。
内容的提问来源于stack exchange,提问作者joeyisplaying
相关产品推荐
相关产品推荐

