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

Quarkus测试中jakarta.ws.rs.core.SecurityContext抛出异常的解决问询

解决Quarkus单元测试中@Context SecurityContext的模拟问题

问题分析

你遇到的IllegalStateException是因为测试环境未初始化JAX-RS请求上下文,导致@Context注入的SecurityContext代理无法获取实际实例。Quarkus的@RequestScoped依赖请求上下文,而单元测试默认不会自动创建该上下文。

解决方案

方法1:用Quarkus测试扩展+@InjectMock模拟

在标注@QuarkusTest的测试类中,通过@InjectMock注入模拟的SecurityContext,并配置其行为:

import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.mockito.InjectMock;
import jakarta.ws.rs.core.SecurityContext;
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.when;

@QuarkusTest
public class YourServiceTest {

    @InjectMock
    SecurityContext securityContext;

    @Inject
    YourRequestScopedBean yourBean;

    @Test
    void testServiceMethod() {
        // 模拟SecurityContext的核心行为
        when(securityContext.getUserPrincipal()).thenReturn(() -> "test-user");
        when(securityContext.isUserInRole("admin")).thenReturn(true);

        // 调用目标方法并执行断言
        yourBean.targetMethod();
    }
}

方法2:手动激活请求上下文(纯单元测试场景)

如果不想启动Quarkus测试容器,可手动创建并绑定请求上下文:

import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.inject.spi.CDI;
import jakarta.ws.rs.core.SecurityContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class YourUnitTest {

    private YourRequestScopedBean yourBean;

    @BeforeEach
    void setUp() {
        // 模拟SecurityContext实例
        SecurityContext mockSecurityCtx = Mockito.mock(SecurityContext.class);
        Mockito.when(mockSecurityCtx.getUserPrincipal()).thenReturn(() -> "test-user");

        // 激活请求上下文并绑定模拟实例
        var beanManager = CDI.current().getBeanManager();
        var requestContext = beanManager.getContext(RequestScoped.class);
        requestContext.activate();
        requestContext.register(mockSecurityCtx, beanManager.createAnnotatedType(SecurityContext.class).getBaseType());

        // 获取RequestScoped Bean实例
        yourBean = CDI.current().select(YourRequestScopedBean.class).get();
    }

    @AfterEach
    void tearDown() {
        // 清理请求上下文
        var requestContext = CDI.current().getBeanManager().getContext(RequestScoped.class);
        requestContext.invalidate();
        requestContext.deactivate();
    }

    @Test
    void testTargetMethod() {
        yourBean.targetMethod();
        // 执行断言逻辑
    }
}

方法3:使用Quarkus TestSecurity注解(推荐)

利用Quarkus内置的@TestSecurity快速初始化带用户身份的SecurityContext:

import io.quarkus.test.security.TestSecurity;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;

@QuarkusTest
public class YourServiceTest {

    @Inject
    YourRequestScopedBean yourBean;

    @Test
    @TestSecurity(user = "test-user", roles = {"admin", "editor"})
    void testWithAuthContext() {
        // 此时SecurityContext已自动初始化,包含指定的用户和角色
        yourBean.targetMethod();
        // 执行断言逻辑
    }
}

关键注意事项

  • @RequestScoped Bean必须在活跃的请求上下文中使用,测试时要么启动Quarkus测试容器(@QuarkusTest),要么手动激活请求上下文
  • 用@InjectMock时,确保目标Bean是通过CDI注入的,而非手动实例化
  • @TestSecurity适合大多数模拟用户身份的场景,无需手动配置SecurityContext的细节

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 17:42:19