4

我正在运行 spring + hibernate + JUnit,springJunit4runner 和事务设置为默认回滚我使用内存中的 derbydb 作为数据库。Hibernate 被用作 JPA 提供程序,我正在成功测试 CRUD 类型的东西。但是,我对 JPA 和 @GeneratedValue 的行为有疑问

如果我单独运行其中一个测试,则两个实体的 id 为 1 和 2。如果我运行整个测试套件,则 id 为 6 和 7。Spring 可以很好地回滚,因此数据库中只有这两个实体添加之后,当然之前为零。但是 @GeneratedValue 的行为不允许我可靠地 findById 除非我从

dao.add(Entity e) //method

为了测试,我不想这样做,或者返回持久存在的实体是一种好习惯,所以无论如何我都应该这样做?

4

3 回答 3

4

在我们的项目中,我们使用内存数据库中的 spring boot 和 h2 进行测试,我们在测试类上使用以下注释解决了这个问题:

@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)

例如:

    @RunWith(SpringRunner.class)
    @AutoConfigureMockMvc
    @SpringBootTest(
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
        classes = Main.class
    )
    @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
    @TestPropertySource(locations = "classpath:application-test.properties")
    public class FooTest {

    }
于 2018-08-02T09:37:52.637 回答
1

您的测试不应该真正依赖于生成的特定 ID 值。ID 分配是数据库和持久层的调用,而不是您做出假设的责任。

不在dao.add(Entity e)实体中设置 ID/主键属性?通常 Hibernate 在存储实体之前设置 ID,至少对于生成的和序列分配的 ID。

(顺便说一句,我强烈建议使用便携式(基于表的)分配器,并且永远不要依赖于特定于数据库的分配机制——序列或自动增量列。便携式分配器工作得更快,并且取决于专有的键分配将使它非常非常更难在不同的数据库上运行。)

一般来说,保存数据的系统确实需要一种知道它被保存到哪个 ID 的方法。否则就没有可靠和独特的方法来检索它,这就是我们首先拥有 PK 的全部原因!

所以你不妨在这一点上找出如何正确地做到这一点。

于 2013-10-19T22:00:31.420 回答
0

我找到了一种方法。手动更改表以重新启动/重置 auto_increment 值。当我使用 Derby DB 时,它是通过以下作为本机查询调用发出的 sql 查询来完成的,因为我如上所述使用 JPA API

em.createNativeQuery("ALTER TABLE konsult ALTER COLUMN id RESTART WITH 1").executeUpdate();

这是不言自明的,但基本上你提供表名和该表的自动递增列,然后选择应该给第一个持久行的值。

这是使用 mysql 的方法: Resetting auto-increment value of MySql database with JPA

不过,我仍然对其他建议持开放态度,因为这是一种 hack,并且在某种程度上依赖于其他测试。它也不是独立于 RDBMS 的。

于 2013-10-19T21:44:51.693 回答