Quarkus JUnit测试中Apache ProducerTemplate模拟失效问题求助
解决Quarkus测试中Mock ProducerTemplate未被引用的问题
问题根源
测试出现Wanted but not invoked错误的核心原因:
MessagingServiceImpl的producerTemplate字段是在onStart方法中通过camelContext.createProducerTemplate()初始化的,使用@QuarkusTest启动测试容器时,会触发StartupEvent执行onStart,创建新的ProducerTemplate实例,完全绕过了你定义的Mock。- 同时混用
@QuarkusTest和MockitoExtension,Quarkus自带Mockito集成,手动添加@ExtendWith(MockitoExtension.class)会导致依赖注入逻辑冲突。
方案1:使用Quarkus原生@InjectMock(推荐)
Quarkus提供io.quarkus.test.junit.mockito.InjectMock注解,可直接将Mock实例注入到被测试Bean中,替代原有依赖:
修正后的测试代码
import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.mockito.InjectMock; import org.apache.camel.CamelContext; import org.apache.camel.ProducerTemplate; import org.junit.jupiter.api.Test; import static org.mockito.Mockito.*; @QuarkusTest public class MessagingServiceImplTest { @Inject MessagingServiceImpl messageServiceImpl; @InjectMock ProducerTemplate producerTemplate; @InjectMock CamelContext camelContext; @Test void submitSourcePaymentTest() { // 模拟camelContext创建Mock的ProducerTemplate when(camelContext.createProducerTemplate()).thenReturn(producerTemplate); // 执行测试方法 String testMsg = "test-payment-message"; messageServiceImpl.submitSourcePayment(testMsg); // 验证调用逻辑,使用类中配置的队列字段而非硬编码 verify(producerTemplate, times(1)) .sendBody(messageServiceImpl.sourceRequestQueue, testMsg); } }
关键说明
- 用
@InjectMock替代@Mock,Quarkus会自动完成Mock实例的注入。 - 必须模拟
camelContext.createProducerTemplate()返回Mock实例,避免onStart方法创建新的真实实例。 - 避免硬编码队列名称,直接复用被测试类的
sourceRequestQueue字段,保证测试与实际代码一致。
方案2:通过反射手动注入Mock
若不想使用Quarkus原生Mock注解,可通过反射直接覆盖私有字段:
测试代码示例
import io.quarkus.test.junit.QuarkusTest; import org.apache.camel.ProducerTemplate; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.lang.reflect.Field; import static org.mockito.Mockito.*; @QuarkusTest public class MessagingServiceImplTest { @Inject MessagingServiceImpl messageServiceImpl; private ProducerTemplate producerTemplate; @BeforeEach void setup() throws NoSuchFieldException, IllegalAccessException { // 创建Mock实例 producerTemplate = mock(ProducerTemplate.class); // 反射设置私有字段 Field field = MessagingServiceImpl.class.getDeclaredField("producerTemplate"); field.setAccessible(true); field.set(messageServiceImpl, producerTemplate); } @Test void submitSourcePaymentTest() { String testMsg = "test-payment-message"; messageServiceImpl.submitSourcePayment(testMsg); verify(producerTemplate, times(1)) .sendBody(messageServiceImpl.sourceRequestQueue, testMsg); } }
关键说明
- 在
@BeforeEach阶段通过反射覆盖producerTemplate字段,替换onStart创建的实例。 - 需处理反射相关异常,代码相对繁琐,适合特殊场景。
额外注意事项
- 若
sourceRequestQueue是私有字段,可同样通过反射获取,或改为包级访问权限(移除private修饰符)。 - 测试中尽量复用被测试类的配置字段,避免硬编码配置值,提升测试稳定性。
内容的提问来源于stack exchange,提问作者Derrick
相关产品推荐
相关产品推荐

