在我们的Spring应用程序中,我们使用一组通用存储库测试来验证使用Spring存储库的最基本用例.其中一个测试验证,如果您try 获取以前删除的实体,则会抛出EntityNotFoundException.

在我们迁移到Spring Boot3和Hibernate6之前,这些测试工作正常,但在更新之后,预期的异常不再被抛出.

您可以使用以下设置重现此行为:

  1. Java(一个简单的实体)
package de.test.hibernate_delete.repository;
import jakarta.persistence.*;
@jakarta.persistence.Entity
@Table(name = "entity")
public class Entity {
    @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) Long id;
    @Version long version;
    @Column(name = "data") String data;
    public Entity(String data) {this.data = data;}
    public Entity() {}
    public Long getId() {return id;}
    public void setId(Long id) {this.id = id;}
    public long getVersion() {return version;}
    public void setVersion(long version) {this.version = version;}
    public String getData() {return data;}
    public void setData(String data) {this.data = data;}
}

  1. EntiryRepository.java(简单JpaRepository)
package de.test.hibernate_delete.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EntityRepository extends JpaRepository<Entity, Long> {
}

  1. Java(导致错误的测试用例)
package de.test.hibernate_delete;

import de.test.hibernate_delete.repository.Entity;
import de.test.hibernate_delete.repository.EntityRepository;
import jakarta.persistence.EntityNotFoundException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import static org.junit.jupiter.api.Assertions.*;

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = HibernateDeleteApplication.class)
public class EntityDeleteTest {
    @Autowired private EntityRepository repository;
    @Test public void testDelete() {
        Entity storedSample = repository.saveAndFlush(new Entity("data"));
        assertNotNull(storedSample.getId());
        repository.delete(storedSample);
        repository.flush();
        assertThrows(EntityNotFoundException.class, () -> assertNull(repository.getOne(storedSample.getId())));
    }
}

测试结果为以下失败消息:

org.opentest4j.AssertionFailedError: Unexpected exception type thrown, 
Expected :class jakarta.persistence.EntityNotFoundException
Actual   :class org.opentest4j.AssertionFailedError

我还将我的最小示例推送到了GitHub回购:https://github.com/LorenzSLA/hibernate_delete_minimal_exampel 失败的测试可以在GitHub Actions Build:https://github.com/LorenzSLA/hibernate_delete_minimal_exampel/actions/runs/6094606983/job/16536481715中看到

Has anyone had similar problems after migrating to Spring Boot 3?

最新情况:

感谢Andreys comment,我更改了测试用例:

    @Test
    public void testDelete() {
        T storedSample = getRepository().saveAndFlush(getSample());
        assertNotNull(storedSample.getId());
        getRepository().delete(storedSample);
        getRepository().flush();

        assertFalse(getRepository().existsById(storedSample.getId()));
    }

推荐答案

这似乎与Hibernate 6没有关系:

repository.getOne(storedSample.getId())方法返回代理对象,实际上不是由活动实体备份的,因此与这样的代理对象的任何交互都将失败,并返回EntityNotFoundException,但问题是您的测试用例实际上正在判断JUNIT断言模块.

assertNull种方法中的Previous implementation种try 通过以下方式报告断言失败:

String stringRepresentation = actual.toString();
if (stringRepresentation == null || stringRepresentation.equals("null")) {
    fail(format(null, actual, message), null, actual);
} else {
    fail(buildPrefix(message) + "expected: <null> but was: <" + actual + ">", null, actual);
}

actual.toString()调用抛出EntityNotFoundException的地方,现在junit使用more accurate way:

catch (Throwable throwable) {
  UnrecoverableExceptions.rethrowIfUnrecoverable(throwable);

  return defaultToString(obj);
}

Java相关问答推荐

当切换javaFX场景时,stage的大小正在Minimize

如何在返回bigint []值的子查询中使用any?

neo4j java驱动程序是否会在错误发生时自动回滚事务?

使用联接和分页的SpringBoot Spring数据JPA

Hibernate EmptyInterceptor可以工作,但不能拦截器

我无法获取我的Java Spring应用程序的Logback跟踪日志(log)输出

为什么Java编译器不区分不同类型的方法?

使用Room Database删除Jetpack合成中的所有项目后,UI未重新合成

%This内置函数示例

Kotlin Val是否提供了与Java最终版相同的可见性保证?

如何在太阳系模拟器中添加月球?

如何在ImageIO或十二只猴子中旋转TIFF CMYK图像?

Spring Validator批注不起作用

每次我需要时创建和关闭数据库连接会有什么效果吗?

在缺少字段时使用Jackson With Options生成Optional.Empty()

本机方法(JNI)总是编译的吗?

JavaFX,GridPane:在GridPane的列中生成元素将保持所有列的宽度

AspectJ编织外部依赖代码,重新打包jar并强制依赖用户使用它

移动二维数组的行

声纳覆盖范围为 0%,未生成 jacoco.xml