Quarkus测试中如何注入Mock列表替换全部实现类
在Quarkus测试中完全替换@All注入的Bean集合
场景说明
现有业务Bean与接口定义如下:
MyService类:
@ApplicationScoped public class MyService { @Inject @All List<MyDataProvider> dataProviders; public List<String> getAllData() { var data = new ArrayList<String>(); for (var provider : dataProviders) { data.add(provider.getData()); } return data; } }
MyDataProvider接口:
public interface MyDataProvider { String getData(); }
当前存在数十个MyDataProvider的实现类,需要在单元测试中用指定的Mock集合完全替换这些真实实现,避免注入未Mock的Bean,仅测试基础功能。
解决方案
方法1:通过@Alternative + 自定义生产者替换集合
创建一个带@Alternative和高优先级的生产者Bean,直接生成你需要的Mock集合,让测试上下文优先使用这个集合而非所有真实实现:
@ApplicationScoped @Alternative @Priority(1) // 优先级高于所有真实Bean(默认真实Bean优先级为0) public class MockDataProviderProducer { @Produces @All List<MyDataProvider> produceMockProviders() { // 定义你需要的Mock实例 MyDataProvider mock1 = () -> "test-data-1"; MyDataProvider mock2 = () -> "test-data-2"; return List.of(mock1, mock2); } }
在测试类中通过@AddBean将该生产者加入测试上下文:
@QuarkusTest @AddBean(MockDataProviderProducer.class) public class MyServiceTest { @Inject MyService myService; @Test void testGetAllData() { List<String> result = myService.getAllData(); assertEquals(2, result.size()); assertTrue(result.contains("test-data-1")); assertTrue(result.contains("test-data-2")); } }
方法2:纯单元测试手动注入依赖
如果不需要启动Quarkus容器做集成测试,直接手动创建MyService实例并注入自定义Mock集合即可,无需依赖容器注入:
import org.junit.jupiter.api.Test; import java.lang.reflect.Field; import java.util.List; import static org.junit.jupiter.api.Assertions.*; public class MyServiceUnitTest { @Test void testGetAllData() { // 构建自定义Mock集合 List<MyDataProvider> mockProviders = List.of( () -> "mock-value-1", () -> "mock-value-2" ); // 初始化服务并注入依赖 MyService myService = new MyService(); try { Field field = MyService.class.getDeclaredField("dataProviders"); field.setAccessible(true); field.set(myService, mockProviders); } catch (NoSuchFieldException | IllegalAccessException e) { fail("Failed to inject mock providers", e); } // 执行测试断言 List<String> result = myService.getAllData(); assertEquals(2, result.size()); assertEquals(List.of("mock-value-1", "mock-value-2"), result); } }
方法3:使用@Mock替代所有实现类(批量Mock)
如果需要用Mockito生成Mock实例,可创建一个带@Mock的实现类,配合@Priority让它覆盖所有真实实现,再手动控制实例数量:
@Mock @ApplicationScoped @Priority(1) public class MockedDataProvider implements MyDataProvider { @Override public String getData() { // 可通过Mockito.when()自定义返回值 return "mocked-data"; } }
然后在测试类中,通过QuarkusMock安装多个实例:
@QuarkusTest public class MyServiceTest { @Inject MyService myService; @BeforeEach void setupMocks() { // 创建多个Mock实例 MyDataProvider mock1 = Mockito.mock(MyDataProvider.class); Mockito.when(mock1.getData()).thenReturn("mock-1"); MyDataProvider mock2 = Mockito.mock(MyDataProvider.class); Mockito.when(mock2.getData()).thenReturn("mock-2"); // 安装Mock,替换所有MyDataProvider实现 QuarkusMock.installMockForType(mock1, MyDataProvider.class); QuarkusMock.installMockForType(mock2, MyDataProvider.class); } @Test void testGetAllData() { List<String> result = myService.getAllData(); assertEquals(2, result.size()); assertTrue(result.contains("mock-1")); assertTrue(result.contains("mock-2")); } }
核心要点
@Alternative+@Priority是Quarkus中替换Bean的标准方式,高优先级的Bean会覆盖低优先级的真实实现。- 纯单元测试手动注入的方式无需启动容器,测试效率更高,适合简单逻辑验证。
- 若使用Mockito,通过
QuarkusMock.installMockForType可批量替换同类型的所有Bean实例。
内容的提问来源于stack exchange,提问作者Ultranium
相关产品推荐
相关产品推荐

