【发布时间】:2022-01-03 07:46:21
【问题描述】:
我在使用 H2 内存数据库测试 Spring JPA (2.5.4) 中的审计注释时遇到问题。我有一个用 @EnableJpaAuditing 注释的主类,以及我的实体的基类。
@Getter
@Setter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class AuditedEntity {
@CreatedDate
LocalDateTime createdDate;
@LastModifiedDate
LocalDateTime lastModifiedDate;
}
两个实体扩展了基类:父类和子类。
@Data
@Entity
@Table(name = "one2many")
class OneToManyEntity extends AuditedEntity {
@Id
@GeneratedValue(strategy = SEQUENCE)
Integer id;
@OneToMany(mappedBy = "parent", cascade = ALL, orphanRemoval = true)
List<ManyToOneEntity> children;
}
@Data
@Entity
@Table(name = "many2one")
class ManyToOneEntity extends AuditedEntity {
@Id
@GeneratedValue(strategy = SEQUENCE)
Integer id;
@ManyToOne(optional = false, fetch = LAZY)
OneToManyEntity parent;
}
父实体的存储库是一个简单的接口声明。
@Repository
interface OneToManyRepository extends CrudRepository<OneToManyEntity, Integer> {
}
我有几个 Spock 测试。
class OneToManyRepoSpec extends Specification {
@Autowired
OneToManyRepository repo
def "test ID is assigned"() {
given:
def parent = new OneToManyEntity()
parent.setChildren([new ManyToOneEntity()])
expect:
def persisted = repo.save(parent)
persisted.getId() > 0
persisted.getLastModifiedDate() != null
}
def "LastModifiedDate value is updated"() {
given:
def persisted1 = repo.save(new OneToManyEntity())
sleep(1000)
persisted1.setChildren([])
def persisted2 = repo.save(persisted1)
expect:
persisted2.lastModifiedDate.isAfter(persisted1.lastModifiedDate)
}
}
我可以通过这些测试中的任何一个,这取决于我如何注释测试类;但我不能让两个测试一起通过。
- 如果我用
@DataJpaTest注释测试类,第一个测试通过(分配了 ID 和审核值),但第二个测试失败(审核值未更新)。 - 如果我用
@SpringBootTest(webEnvironment = NONE)注释测试类,第一个测试失败(ConstraintViolationException: NULL not allowed for column "parent_id";因此未分配 ID),但第二个测试通过(更新审核值)。
我是否必须将这些测试拆分为具有不同注释的不同类,或者有没有办法将它们放在一起并通过?我也有兴趣进一步了解导致这些单独测试失败的原因。
【问题讨论】:
-
我知道 Spock,但不知道 Spring 和/或 JPA。我认为在 GitHub 上发布 MCVE 对您会有所帮助,最好是一个 Maven 项目(Gradle,如果必须的话)。那么我可以看看,如果伦纳德不是更快。反正他知道的更多。顺便说一句,如果您实际上将
ManyToOneEntity指向其父级以实现引用完整性,ConstraintViolationException会消失吗? -
是的,手动分配
child.setParent(parent)是@SpringBootTest方案的解决方法。假期过后,我将致力于发布 GitHub 存储库。感谢您的观看。 -
我认为您的问题是,
@DataJpaTest被注释为@Transactional导致整个测试在单个事务中运行。 -
@LeonardBrünings,这是一个很好的观察:
@Transactional似乎是两个注释之间的区别。但是为什么一个事务会导致第二个测试失败呢? -
@kriegaex,我在这里创建了一个 GitHub 项目:github.com/jaco0646/jpa-audit-test。
标签: java spring-boot spring-data-jpa spock audit