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

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状态残留也会干扰后续测试。

修复步骤

  1. 删除@BeforeAll中的手动激活上下文代码,依赖@ActivateRequestContext为每个测试方法单独激活上下文
  2. 添加@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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 18:17:04