我正在使用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],
因此由于某种原因,此错误仅被包装并记录。使用存储库进行持久化时,如何使其“解开”并抛出?
答案 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)
参加我的测试班。