Quarkus @QuarkusTest执行第二个测试时始终抛出ContextNotActiveException
Quarkus请求作用域Bean单元测试上下文异常问题
环境
- Quarkus 2.16.12
- Java 17
问题场景
我是Quarkus新手,正在给带@RequestScoped注解的ConfigRS类写单元测试。单独跑每个测试都能成功,但连续执行两个测试时,第二个总会报请求上下文未激活的错误,调换测试顺序后问题依然存在。
待测试Bean代码
@RequestScoped @Path("/config") @Produces(MediaType.APPLICATION_JSON) public class ConfigRS { // ... 其他业务代码 @GET @Path("load") public ConfigResponse apiLoad() { final ConfigResponse response = new ConfigResponse(); // ... 核心业务逻辑实现 } }
测试代码
package com.deltaone; import com.deltaone.blackbox.web.config.ConfigException; import com.deltaone.blackbox.web.config.ConfigFile; import com.deltaone.blackbox.web.config.ConfigRS; import io.quarkus.arc.Arc; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.mockito.InjectSpy; import org.junit.jupiter.api.*; import javax.enterprise.context.control.ActivateRequestContext; import java.util.ArrayList; import java.util.List; import static io.restassured.RestAssured.given; import static org.mockito.Mockito.*; @QuarkusTest @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class ConfigRSTest { @InjectSpy ConfigRS crs; @BeforeAll static void beforeAll() { Arc.container().requestContext().activate(); } @Test @ActivateRequestContext @Order(1) public void SuccessLoadFromHdfs() throws Exception { doNothing().when(crs).loadFileFromHdfs(); List<ConfigFile> mockFiles = new ArrayList<>(); mockFiles.add(new ConfigFile()); doReturn(mockFiles).when(crs).readConfigInfo(); given() .when().get("/portal/config/load") .then() .body("status", org.hamcrest.Matchers.equalTo("ok")) .statusCode(200); } @Test @ActivateRequestContext @Order(2) public void FailedLoadFromHdfs() throws Exception { doThrow(new ConfigException("Load failed")).when(crs).loadFileFromHdfs(); given() .when().get("/portal/config/load") .then() .body("status", org.hamcrest.Matchers.equalTo("error")) .statusCode(200); } }
核心错误信息
Caused by: javax.enterprise.context.ContextNotActiveException: RequestScoped context was not active when trying to obtain a bean instance for a client proxy of CLASS bean [class=com.empirix.redbox.web.config.ConfigRS, id=688d9526726460b2949d045bc5749a6c249737c7] - you can activate the request context for a specific method using the @ActivateRequestContext interceptor binding
解决方案
问题根源在于@BeforeAll中激活的请求上下文属于测试类全局生命周期,第一个测试结束后Quarkus会自动销毁该上下文,导致第二个测试执行时上下文已失效。同时测试间的Mock状态残留也会干扰后续测试。
修复步骤
- 删除
@BeforeAll中的手动激活上下文代码,依赖@ActivateRequestContext为每个测试方法单独激活上下文 - 添加
@AfterEach方法,重置Mock状态并销毁当前请求上下文,确保每个测试拥有独立干净的环境
修改后的测试类代码:
@QuarkusTest @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class ConfigRSTest { @InjectSpy ConfigRS crs; @AfterEach void afterEach() { // 重置Mock,清除上一个测试的状态残留 reset(crs); // 销毁当前请求上下文,为下一个测试准备干净环境 Arc.container().requestContext().ifActive(ctx -> ctx.destroy()); } @Test @ActivateRequestContext @Order(1) public void SuccessLoadFromHdfs() throws Exception { doNothing().when(crs).loadFileFromHdfs(); List<ConfigFile> mockFiles = new ArrayList<>(); mockFiles.add(new ConfigFile()); doReturn(mockFiles).when(crs).readConfigInfo(); given() .when().get("/portal/config/load") .then() .body("status", org.hamcrest.Matchers.equalTo("ok")) .statusCode(200); } @Test @ActivateRequestContext @Order(2) public void FailedLoadFromHdfs() throws Exception { doThrow(new ConfigException("Load failed")).when(crs).loadFileFromHdfs(); given() .when().get("/portal/config/load") .then() .body("status", org.hamcrest.Matchers.equalTo("error")) .statusCode(200); } }
原理说明
@ActivateRequestContext会为每个测试方法单独创建并激活请求上下文,避免全局上下文的生命周期冲突@AfterEach中的重置和销毁操作,彻底隔离了测试间的状态,保证每个测试都在独立环境中执行
内容的提问来源于stack exchange,提问作者nbe
相关产品推荐
相关产品推荐

