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(); // 执行断言逻辑 } }
关键注意事项
@RequestScopedBean必须在活跃的请求上下文中使用,测试时要么启动Quarkus测试容器(@QuarkusTest),要么手动激活请求上下文- 用
@InjectMock时,确保目标Bean是通过CDI注入的,而非手动实例化 @TestSecurity适合大多数模拟用户身份的场景,无需手动配置SecurityContext的细节
内容的提问来源于stack exchange,提问作者toleador
相关产品推荐
相关产品推荐

