在测试之间重置JPA生成的值

时间:2013-10-19 20:18:33

标签: java spring hibernate jpa junit4

我正在使用springJunit4runner运行spring + hibernate + JUnit,并将事务设置为默认回滚我使用内存中的derbydb作为数据库。 Hibernate用作JPA Provider,我成功测试了CRUD类的东西。但是,我遇到了JPA和@GeneratedValue

的行为问题

如果我单独运行我的一个测试,那么两个实体将持久存在,标识为1和2.如果我运行整个测试套件,那么id为6和7. Spring确实回滚很好,所以只有这两个实体在添加后的数据库中,当然在之前为零。但@GeneratedValue的行为不允许我使用可靠的findById,除非我从

返回Id
dao.add(Entity e) //method

我不想为了测试而这样做,或者返回持久化的实体是一个好习惯,所以我应该这样做呢?

3 个答案:

答案 0 :(得分:1)

您的测试不应该依赖于生成的特定ID值.ID分配是数据库&持久层呼叫,&没有责任做出假设。

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

(顺便说一下,我强烈建议使用便携式(基于表格的)分配器和永远,具体取决于特定于数据库的分配机制 - 序列或自动增量列。便携式分配器工作速度更快,并且取决于专有密钥分配将使得在不同的数据库上运行变得非常困难。)

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

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

答案 1 :(得分: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

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

答案 2 :(得分:0)

在我们的项目中,我们使用spring boot和内存db中的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 {

    }