添加 @Transactional 通过阻止 JPA 获取外键来破坏单元测试
Adding @Transactional is breaking UnitTests by stopping JPA from fetching the foreign keys
我正在尝试提高飞路数据库测试的速度。原来的方法是运行flyway.clear()
和flyway.migrate()
每次测试之间运行。不过现在的问题是我们有一些可能很长的 运行ning flyway 迁移脚本,我们不想在每次测试之间重新 运行 那些。
我一直在尝试使用spring @Transactional 注解在每次测试后回滚数据库,那么我们只需要运行 flyway 一次。
问题是,一旦我围绕测试添加事务,JPA 就会停止获取外键。我假设这是因为嵌套事务没有按照我的预期运行,但我无法弄清楚我配置错误的地方。
我在这里发布了一个示例项目:ExampleSpringJpaHibernatePostgresqltest 有问题(参见 ExampleTest.java
)但总而言之:
我有如下带有外键的实体(我删除了不必要的内容以使其更易于阅读):
@Entity
@Table(name = "parent")
public class ParentEntity {
@Id
@Column
private Integer id;
@Column
private String name;
@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "fk_parent", referencedColumnName = "id")
private Set<ChildEntity> children;
}
@Entity
@Table(name = "child")
public class ChildEntity {
@Id
@Column
private Integer id;
@Column
private String name;
@Column(name = "fk_parent")
private Integer fkParent;
}
然后我有一个使用 parentRepository.findAll()
的测试。如果我使用 @Transactional
围绕该测试,则测试失败,因为 parentEntity.getChildren()
为空。尽管没有事务,并且 运行ning flyway clear/migrate 在每次测试之间一切都按预期工作。
@Test
@Transactional
public void testReadWithDependencies() {
ParentEntity savedParent1 = parentRepo.save(new ParentEntity("parent1"));
childRepo.save(new ChildEntity("child1", savedParent1.getId()));
Set<ChildEntity> acutalChildren = parentRepo.findAll().get(0).getChildren();
// XXX When the tests are run with @Transactional, this assertion fails.
assertThat(acutalChildren).isNotNull();
}
parentRepo.findAll
不会从数据库中刷新数据,也不会将子项添加到父项中的子项中。
因此没有子实体分配给父实体。
因此,如果您刷新实体(我注入了 EntityManger),您的测试就会成功:
@Test
@Transactional
public void testReadWithDependencies() {
assertThat(parentRepo.findAll()).isEmpty();
assertThat(childRepo.findAll()).isEmpty();
ParentEntity savedParent1 = parentRepo.save(new ParentEntity("parent1"));
childRepo.save(new ChildEntity("child1", savedParent1.getId()));
List<ParentEntity> allParents = parentRepo.findAll();
assertThat(allParents).hasSize(1);
// Refresh
ParentEntity parentEntity = allParents.get(0);
entityManager.refresh(parentEntity);
Set<ChildEntity> acutalChildren = parentEntity.getChildren();
// XXX When the tests are run with @Transactional, this assertion fails.
assertThat(acutalChildren).isNotNull();
assertThat(acutalChildren).hasSize(1);
assertThat(acutalChildren.iterator().next().getName()).isEqualTo("child1");
}
我正在尝试提高飞路数据库测试的速度。原来的方法是运行flyway.clear()
和flyway.migrate()
每次测试之间运行。不过现在的问题是我们有一些可能很长的 运行ning flyway 迁移脚本,我们不想在每次测试之间重新 运行 那些。
我一直在尝试使用spring @Transactional 注解在每次测试后回滚数据库,那么我们只需要运行 flyway 一次。
问题是,一旦我围绕测试添加事务,JPA 就会停止获取外键。我假设这是因为嵌套事务没有按照我的预期运行,但我无法弄清楚我配置错误的地方。
我在这里发布了一个示例项目:ExampleSpringJpaHibernatePostgresqltest 有问题(参见 ExampleTest.java
)但总而言之:
我有如下带有外键的实体(我删除了不必要的内容以使其更易于阅读):
@Entity
@Table(name = "parent")
public class ParentEntity {
@Id
@Column
private Integer id;
@Column
private String name;
@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "fk_parent", referencedColumnName = "id")
private Set<ChildEntity> children;
}
@Entity
@Table(name = "child")
public class ChildEntity {
@Id
@Column
private Integer id;
@Column
private String name;
@Column(name = "fk_parent")
private Integer fkParent;
}
然后我有一个使用 parentRepository.findAll()
的测试。如果我使用 @Transactional
围绕该测试,则测试失败,因为 parentEntity.getChildren()
为空。尽管没有事务,并且 运行ning flyway clear/migrate 在每次测试之间一切都按预期工作。
@Test
@Transactional
public void testReadWithDependencies() {
ParentEntity savedParent1 = parentRepo.save(new ParentEntity("parent1"));
childRepo.save(new ChildEntity("child1", savedParent1.getId()));
Set<ChildEntity> acutalChildren = parentRepo.findAll().get(0).getChildren();
// XXX When the tests are run with @Transactional, this assertion fails.
assertThat(acutalChildren).isNotNull();
}
parentRepo.findAll
不会从数据库中刷新数据,也不会将子项添加到父项中的子项中。
因此没有子实体分配给父实体。
因此,如果您刷新实体(我注入了 EntityManger),您的测试就会成功:
@Test
@Transactional
public void testReadWithDependencies() {
assertThat(parentRepo.findAll()).isEmpty();
assertThat(childRepo.findAll()).isEmpty();
ParentEntity savedParent1 = parentRepo.save(new ParentEntity("parent1"));
childRepo.save(new ChildEntity("child1", savedParent1.getId()));
List<ParentEntity> allParents = parentRepo.findAll();
assertThat(allParents).hasSize(1);
// Refresh
ParentEntity parentEntity = allParents.get(0);
entityManager.refresh(parentEntity);
Set<ChildEntity> acutalChildren = parentEntity.getChildren();
// XXX When the tests are run with @Transactional, this assertion fails.
assertThat(acutalChildren).isNotNull();
assertThat(acutalChildren).hasSize(1);
assertThat(acutalChildren.iterator().next().getName()).isEqualTo("child1");
}