Spring Boot集成内嵌MongoDB时JUnit测试失败求助
在Spring Boot 2.7.10项目中使用版本2.2.0的de.flapdoodle.embed.mongo配置内嵌MongoDB,配置类代码如下:
@Configuration public class TestMongoConfig { private MongodExecutable mongodExecutable; private MongoClient mongoClient; @Value("${mongo.db.host:localhost}") private String mongoHost; @Value("${mongo.db.port:27017}") private int mongoPort; @Value("${mongo.db.database:test}") private String mongoDatabase; @PostConstruct public void setup() throws Exception { MongodStarter starter = MongodStarter.getDefaultInstance(); IMongodConfig mongodConfig = new MongodConfigBuilder() .version(Version.Main.V3_2) .net(new Net(mongoHost, mongoPort, Network.localhostIsIPv6())) .build(); mongodExecutable = starter.prepare(mongodConfig); mongodExecutable.start(); String connectionString = "mongodb://" + mongoHost + ":" + mongoPort; mongoClient = MongoClients.create(connectionString); } @PreDestroy public void cleanup() { mongodExecutable.stop(); mongoClient.close(); } @Bean public MongoTemplate mongoTemplate() { return new MongoTemplate(mongoClient, mongoDatabase); } }
测试类通过@Autowired注入MongoTemplate后,部分测试失败,报错信息:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testMongoConfig': Invocation of init method failed; nested exception is java.io.IOException: Could not start process: failed errno:10048 Only one usage of each socket address (protocol/network address/port) is normally permitted. for socket: 127.0.0.1:27017
2023-04-04T10:11:42.087+0530 E STORAGE [initandlisten] Failed to set up sockets during startup.
解决方案
1. 使用随机端口替代固定端口
问题根源是多测试并行执行时,同一固定端口被重复占用。修改配置让内嵌Mongo自动分配可用随机端口:
@Configuration public class TestMongoConfig { private MongodExecutable mongodExecutable; private MongoClient mongoClient; @Value("${mongo.db.host:localhost}") private String mongoHost; @Value("${mongo.db.database:test}") private String mongoDatabase; @PostConstruct public void setup() throws Exception { MongodStarter starter = MongodStarter.getDefaultInstance(); // 自动获取随机可用端口 IMongodConfig mongodConfig = new MongodConfigBuilder() .version(Version.Main.V3_2) .net(new Net(mongoHost, Network.getFreeServerPort(), Network.localhostIsIPv6())) .build(); mongodExecutable = starter.prepare(mongodConfig); mongodExecutable.start(); // 获取实际分配的端口创建连接 int actualPort = mongodConfig.net().getPort(); String connectionString = "mongodb://" + mongoHost + ":" + actualPort; mongoClient = MongoClients.create(connectionString); } @PreDestroy public void cleanup() { if (mongodExecutable != null) { mongodExecutable.stop(); } if (mongoClient != null) { mongoClient.close(); } } @Bean public MongoTemplate mongoTemplate() { return new MongoTemplate(mongoClient, mongoDatabase); } }
关键改动:用Network.getFreeServerPort()自动获取未被占用的端口,避免固定端口冲突。
2. 保证测试上下文隔离
如果使用JUnit 5,给测试类添加@DirtiesContext注解,确保每个测试方法执行后销毁Spring上下文,避免不同测试共享Mongo实例:
@SpringBootTest @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) public class YourMongoTest { @Autowired private MongoTemplate mongoTemplate; // 测试方法实现... }
3. 排查外部端口占用
检查本地是否有独立的MongoDB服务正在运行,若存在会占用27017端口。可以关闭外部Mongo服务,或者临时修改配置使用其他固定端口(优先推荐随机端口方案)。
内容的提问来源于stack exchange,提问作者Yatharth Mishra

