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

Quarkus测试中Singleton转ApplicationScoped失败问题求助

问题分析与解决方案

问题原因

你的场景中@InjectMock(convertScopes = true)失效,核心原因是RestClient的Singleton作用域是通过application.properties配置项声明的,而非直接在接口上用注解标注。Quarkus的@InjectMock的convertScopes参数仅能识别并转换通过注解(比如@Singleton)声明的作用域,对配置文件中动态设置的作用域无法处理,因此仍然会识别到原Singleton作用域,触发CDI作用域校验错误。

解决方案

方案1:将RestClient的作用域改为注解声明(推荐)

把application.properties中的作用域配置移除,直接在RpoService接口上添加@Singleton注解:

@Path("api/rpo/registerdata/public/{filename}")
@RegisterRestClient(configKey = "gpo.upload")
@ClientHeaderParam(name = "Authorization", value = "{pe.dev.rpo.gpo.JwtStore.getBearer}")
@Singleton // 直接用注解声明作用域
public interface RpoService {
    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    Response upload(InputStream inputStream, @PathParam("filename") String filename);
}

同时删除application.properties中的对应配置:

# 删除这一行
# gpo.upload/mp-rest/scope=javax.inject.Singleton

这样@InjectMock(convertScopes = true)就能正常识别并将Singleton转换为ApplicationScoped,Mock就能正常注入。

方案2:自定义Mock实现类替代RestClient

如果必须保留配置文件中的作用域设置,可以创建一个Mock实现类,通过Quarkus的@Mock注解替换原RestClient:

  1. 创建Mock实现类:
@Mock
@ApplicationScoped
@RegisterRestClient(configKey = "gpo.upload")
public class MockRpoService implements RpoService {
    @Override
    public Response upload(InputStream inputStream, String filename) {
        // 这里可以根据测试需求返回预设的Response,或者用Mockito增强
        Response mockResponse = Mockito.mock(Response.class);
        Mockito.when(mockResponse.getStatus()).thenReturn(201);
        return mockResponse;
    }
}
  1. 在测试类中直接注入这个Mock类(或者依然注入原接口,Quarkus会自动替换为Mock实现):
@QuarkusTest
public class ExportServiceTest {
    @Inject
    ExportService exportService;

    @Inject
    @RestClient
    RpoService ax; // 此时注入的是MockRpoService实例

    @Test
    void test_upload() throws IOException {
        File f = File.createTempFile("some-prefix", "some-ext");
        Path p = f.toPath();
        FileInputStream inputStream = new FileInputStream(f);
        String fileName = "randomstring";
        
        exportService.uploadDelete(p, fileName);
        assertThat(ax.upload(inputStream, fileName).getStatus()).isEqualTo(201);
        
        f.deleteOnExit();
    }
}

如果需要动态设置Mock行为,可以在测试类中用Mockito的spy包装这个Mock实例:

@Inject
@RestClient
RpoService ax;

@BeforeEach
void setup() {
    ax = Mockito.spy(ax);
}

@Test
void test_upload() throws IOException {
    // 动态修改Mock行为
    Response customResponse = Mockito.mock(Response.class);
    Mockito.when(customResponse.getStatus()).thenReturn(400);
    Mockito.when(ax.upload(any(InputStream.class), anyString())).thenReturn(customResponse);
    
    // 测试逻辑...
}

方案3:升级Quarkus版本

部分旧版本的Quarkus存在@InjectMock(convertScopes = true)对配置式作用域支持不足的问题,建议升级到Quarkus 2.16.x及以上版本,该问题在后续版本中已被修复。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 02:05:27