测试Hibernate @Check约束时无法生成约束违规异常

时间:2018-11-10 09:10:49

标签: java hibernate spring-boot jpa h2

我正在使用Hibernate @Check批注,但是当不满足约束条件时,我的测试不会失败。当前仅在H2数据库中使用默认的Spring引导配置。

我想念什么?在save(..)之后应该有某种 flush 吗?

运行测试时,我看到表已正确创建。如果我从日志中复制创建行,并使用它创建一个表到我的“真实” Postgres数据库中,我可以测试不同的插入,并看到该行在有约束的情况下都很好。

实体

@Getter @Setter
@Entity @Check(constraints = "a IS NOT NULL OR b IS NOT NULL")
public class Constrained {

    @Id @GeneratedValue
    private Long id;

    private String a, b;
}

测试

@DataJpaTest
@RunWith(SpringRunner.class)
public class HibernateCheckTest {

    @Resource // this repo is just some boiler plate code but attached at 
              // the bottom of question
    private ConstrainedRepository repo;

    @Test @Transactional // also tried without @Transactional
    public void test() {
        Constrained c = new Constrained();
        repo.save(c); // Am I wrong to expect some constraint exception here?
    }
}

运行测试时的表生成脚本

  

受约束的创建表(id bigint不为null,varchar(255),b   varchar(255),主键(id),检查(a IS NOT NULL或b IS NOT   NULL))

存储库(在存储库中看不到太多,只是为了显示它):

public interface ConstrainedRepository
            extends CrudRepository<Constrained, Long> {
}

如何

如果我使用EntityManager,那么将其添加到测试类中:

@PersistenceContext
private EntityManager em;

并像这样进行持久化:

em.persist(c);
em.flush();

我会得到一个例外,而不是repo.save(c)

AND

使用repo.save(c)更仔细地研究原始测试中的日志:

  

org.springframework.test.context.transaction.TransactionContext:139-测试的回滚事务:
  ...
  testException = [null],

因此由于某种原因,此错误仅被包装并记录。使用存储库进行持久化时,如何使其“解开”并抛出?

2 个答案:

答案 0 :(得分:2)

ConstrainedRepository中,扩展JpaRepository而不是CrudRepository,然后使用:

repo.saveAndFlush(c);

代替:

repo.save(c);

该检查是在数据库中强制执行的,只有在将更改(在本例中为INSERT语句)刷新到数据库时才发生。

在没有显式刷新的情况下,Hibernate will defer将语句发送到数据库,直到提交事务或执行查询为止。

但是,从Spring DataJpaTest文档中:

  

默认情况下,数据JPA测试是事务性的,并在最后回滚   每次测试。

因此,在这种情况下,没有提交。事务将回滚,并且永远不会将语句刷新到数据库,因此永远不会引发异常。

答案 1 :(得分:2)

感谢 codemonkey answer,我找到了解决方案。通过添加以下内容来解决:

@org.springframework.transaction.annotation.Transactional(propagation = 
                                                     Propagation.NOT_SUPPORTED)

参加我的测试班。