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

Quarkus测试中PanacheEntity未持久化问题求助

解决Quarkus测试中RestEasy请求看不到测试数据的问题

你猜的没错!核心问题就是事务上下文隔离——测试方法里的@Transactional是跑在测试专属的本地事务里,而通过RestEasy发的HTTP请求会触发一个完全独立的应用事务。测试的事务默认会在测试结束后回滚,而且在HTTP请求执行时,测试的事务还处于未提交状态,所以应用端的服务根本看不到你插入的User数据。

下面给你两个可行的解决方案,推荐第一个:

方案1:用Quarkus专属的@TestTransaction注解

Quarkus专门为这种场景提供了io.quarkus.test.TestTransaction注解,它会自动帮你处理事务同步:测试代码里的数据库操作会在HTTP请求发送前提交,测试结束后又自动回滚,完全不会污染测试环境。

修改你的测试方法就行,只需要加一个注解:

@Test
@TestTransaction // 关键就是这个注解
public void testWithValidAuthenticationChallenge() {
    User user = User.builder()
            .name("admin")
            .role(Roles.ADMIN)
            .status(Status.ACTIVE)
            .password(BCrypt.withDefaults().hashToString(10, "admin".toCharArray()))
            .email("admin@admin.com")
            .build();

    user.persistAndFlush(); // 现在这个操作会在HTTP请求前提交,服务能查到数据了

    given()
            .when()
            .contentType(ContentType.JSON)
            .body(AuthenticationChallenge.builder().email("admin@admin.com").password("admin").build())
            .post(url)
            .then()
            .statusCode(200)
            .log()
            .all();
}

方案2:手动控制事务提交(不推荐,除非特殊场景)

如果你不想用@TestTransaction,也可以手动提交测试事务,但要记得测试结束后清理数据,避免影响其他测试用例:

import jakarta.persistence.EntityManager;
import jakarta.inject.Inject;

// 先注入EntityManager
@Inject
EntityManager em;

@Test
@Transactional
public void testWithValidAuthenticationChallenge() {
    User user = User.builder()
            .name("admin")
            .role(Roles.ADMIN)
            .status(Status.ACTIVE)
            .password(BCrypt.withDefaults().hashToString(10, "admin".toCharArray()))
            .email("admin@admin.com")
            .build();

    user.persistAndFlush();
    em.getTransaction().commit(); // 手动提交事务,让服务能看到数据

    try {
        given()
                .when()
                .contentType(ContentType.JSON)
                .body(AuthenticationChallenge.builder().email("admin@admin.com").password("admin").build())
                .post(url)
                .then()
                .statusCode(200)
                .log()
                .all();
    } finally {
        // 测试结束后手动清空数据
        em.getTransaction().begin();
        User.deleteAll();
        em.getTransaction().commit();
    }
}

补充说明

你的@BeforeEach方法用@Transactional没问题,因为它会在每个测试前执行并自动回滚,刚好能清空数据库,不会干扰其他测试。但测试方法里的事务和HTTP请求的事务是完全隔离的,这就是为什么你在测试里能查到数据,服务里却查不到的原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:42:52