Quarkus单元测试:如何解决注入引发的数据库连接问题?
Quarkus单元测试注入Service触发数据库连接失败问题
问题描述
单元测试本无需连接数据库,但注入MerchantService时,Quarkus自动尝试连接数据库,报错:
io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: localhost/127.0.0.1:3306
测试类代码:
@QuarkusTest class MyTestClass { @InjectMock MerchantRepository merchantRepository; @Inject MerchantService merchantService; // 问题出在此注入环节 @Inject MerchantMapper merchantMapper; @Test void testupdate() { MerchantDTO merchantDTO = new MerchantDTO(); merchantDTO.setId("id"); merchantDTO.setSomething2("hello"); merchantDTO.setSomething3("hello"); merchantDTO.setSomething4("hello"); merchantDTO.setSomething5(false); String id = "id"; MerchantBO merchant = merchantMapper.toBOFromDTO(merchantDTO); MerchantBO fake = null; when(merchantRepository.somemethod(merchantDTO.getId())).thenReturn(Uni.createFrom().item(merchant)); when(merchantRepository.somemethod2(Mockito.any(), Mockito.any())).thenReturn(Uni.createFrom().item(fake)); when(merchantRepository.somemethod3(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(Uni.createFrom().item(fake)); assertEquals(merchantDTO, merchantService.update(id, merchantDTO).await().indefinitely()); } }
Service类代码:
@ApplicationScoped public class MerchantService { @Inject MerchantRepository merchantRepository; @Inject MerchantMapper merchantMapper; ... }
解决方案
方案1:纯单元测试(不启动Quarkus容器)
直接手动实例化Service并注入Mock依赖,完全避开Quarkus容器的初始化逻辑,从根源上杜绝数据库连接尝试:
class MyTestClass { private MerchantRepository merchantRepository = Mockito.mock(MerchantRepository.class); // 如果MerchantMapper是纯DTO/BO转换类,可直接用真实实例,无需Mock private MerchantMapper merchantMapper = new MerchantMapperImpl(); private MerchantService merchantService = new MerchantService(); @BeforeEach void setup() { // 手动注入Service的依赖 merchantService.merchantRepository = merchantRepository; merchantService.merchantMapper = merchantMapper; } @Test void testupdate() { MerchantDTO merchantDTO = new MerchantDTO(); merchantDTO.setId("id"); merchantDTO.setSomething2("hello"); merchantDTO.setSomething3("hello"); merchantDTO.setSomething4("hello"); merchantDTO.setSomething5(false); String id = "id"; MerchantBO merchant = merchantMapper.toBOFromDTO(merchantDTO); MerchantBO fake = null; when(merchantRepository.somemethod(merchantDTO.getId())).thenReturn(Uni.createFrom().item(merchant)); when(merchantRepository.somemethod2(Mockito.any(), Mockito.any())).thenReturn(Uni.createFrom().item(fake)); when(merchantRepository.somemethod3(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(Uni.createFrom().item(fake)); assertEquals(merchantDTO, merchantService.update(id, merchantDTO).await().indefinitely()); } }
方案2:保留@QuarkusTest,禁用数据库相关扩展
如果必须使用@QuarkusTest(比如需要Quarkus上下文支持),在测试配置中禁用数据库扩展或配置无操作数据源:
在src/test/resources/application.properties添加:
# 禁用JDBC数据源 quarkus.datasource.jdbc=false quarkus.datasource.db-kind=none # 禁用Hibernate ORM(如果使用了) quarkus.hibernate-orm.active=false # 启用Panache Mock(如果Repository是PanacheRepository) quarkus.panache.mock-active=true
配置后,Quarkus启动时不会尝试初始化数据库连接,同时@InjectMock会正确替换真实的Repository Bean。
方案3:检查Repository的初始化逻辑
如果Repository带有@PostConstruct等初始化方法,即使被Mock,Quarkus可能仍会执行真实Bean的初始化逻辑。此时可以跳过这些方法:
@QuarkusTest class MyTestClass { @InjectMock MerchantRepository merchantRepository; @Inject MerchantService merchantService; @Inject MerchantMapper merchantMapper; @BeforeEach void setup() { // 跳过Repository的初始化方法(假设方法名为init) Mockito.doNothing().when(merchantRepository).init(); } // 测试方法不变 }
内容的提问来源于stack exchange,提问作者Mountain65
相关产品推荐
相关产品推荐

