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

Quarkus中Mock MutinyEmitter遇CDI异常,如何完成单元测试?

解决Dependent作用域下MutinyEmitter的单元测试问题

针对你遇到的Dependent作用域Bean无法被Mockito的@InjectMocks正常注入的问题,下面提供几种实用的解决方法:

方法一:用Quarkus官方Mock扩展(推荐,适合Quarkus环境)

如果你的项目基于Quarkus,直接用官方提供的测试扩展就能避开作用域冲突问题,这是最省心的方案:

  1. 测试类添加@QuarkusTest注解,开启Quarkus测试上下文
  2. 用@InjectMock结合@Channel创建对应通道的Mock实例
  3. 注入待测试的PaymentReversalService,调用方法后验证Mock的调用情况

代码示例:

import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.mockito.InjectMock;
import io.smallrye.mutiny.Uni;
import io.smallrye.reactive.messaging.MutinyEmitter;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import javax.inject.Inject;
import org.eclipse.microprofile.reactive.messaging.Channel;

@QuarkusTest
public class PaymentReversalServiceTest {

    @InjectMock
    @Channel("payment-reversal-channel") // 替换为你实际的通道名称
    MutinyEmitter<Payment> mockEmitter;

    @Inject
    PaymentReversalService service;

    @Test
    void testReverse() {
        Payment testPayment = new Payment();
        // 预设Mock的send方法返回值
        Mockito.when(mockEmitter.send(Mockito.any(Payment.class))).thenReturn(Uni.createFrom().item(testPayment));

        // 调用待测试方法
        Uni<Payment> result = service.reverse(testPayment);

        // 验证Mock调用和结果
        result.subscribe().with(payment -> {
            Mockito.verify(mockEmitter, Mockito.times(1)).send(testPayment);
        });
    }
}

方法二:手动注入Mock(纯Mockito环境通用)

如果不想依赖Quarkus测试扩展,直接手动实例化服务并注入Mock,完全绕开CDI作用域限制:

  1. 用Mockito创建MutinyEmitter的Mock实例
  2. 实例化PaymentReversalService
  3. 用反射工具(比如Mockito自带的ReflectionTestUtils)把Mock注入到服务的对应字段
  4. 执行测试并验证

代码示例:

import io.smallrye.mutiny.Uni;
import io.smallrye.reactive.messaging.MutinyEmitter;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.test.util.ReflectionTestUtils;

public class PaymentReversalServiceTest {

    @Test
    void testReverse() {
        // 创建Mock Emitter
        MutinyEmitter<Payment> mockEmitter = Mockito.mock(MutinyEmitter.class);
        Payment testPayment = new Payment();
        Mockito.when(mockEmitter.send(testPayment)).thenReturn(Uni.createFrom().item(testPayment));

        // 实例化待测试服务并注入Mock
        PaymentReversalService service = new PaymentReversalService();
        ReflectionTestUtils.setField(service, "emitter", mockEmitter); // "emitter"为服务中对应字段名

        // 执行测试并验证
        service.reverse(testPayment).await().indefinitely();
        Mockito.verify(mockEmitter, Mockito.times(1)).send(testPayment);
    }
}

如果你的PaymentReversalService支持构造器注入(把Emitter作为构造参数),直接通过构造器传入Mock实例即可,无需反射,代码会更简洁。

方法三:自定义CDI生产者(适合复杂CDI测试场景)

如果必须在CDI测试上下文运行,可以自定义生产者提供Mock实例,覆盖原通道的注入:

  1. 在测试类中创建CDI生产者方法,标注@Produces和@Channel,返回Mock的MutinyEmitter
  2. 给生产者设置@ApplicationScoped作用域,避免Dependent作用域问题
  3. 注入服务进行测试

代码示例:

import io.smallrye.mutiny.Uni;
import io.smallrye.reactive.messaging.MutinyEmitter;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import org.eclipse.microprofile.reactive.messaging.Channel;

public class PaymentReversalServiceTest {

    private final MutinyEmitter<Payment> mockEmitter = Mockito.mock(MutinyEmitter.class);

    @Produces
    @Channel("payment-reversal-channel")
    @ApplicationScoped
    public MutinyEmitter<Payment> produceMockEmitter() {
        return mockEmitter;
    }

    @Inject
    PaymentReversalService service;

    @Test
    void testReverse() {
        Payment testPayment = new Payment();
        Mockito.when(mockEmitter.send(testPayment)).thenReturn(Uni.createFrom().item(testPayment));

        service.reverse(testPayment).await().indefinitely();
        Mockito.verify(mockEmitter).send(testPayment);
    }
}

内容的提问来源于stack exchange,提问作者Allan Juan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 12:47:11