You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 10:55:17