在单元测试中调用Spring Repository.save()时未触发Hibernate Validator

Pau*_*aul 5 java validation spring spring-data spring-boot

这是我的实体:

@Builder
@Data
@Entity
@Table(name = "audit_log")
public class AuditEventEntity {
    @Id
    @GeneratedValue
    private UUID id;

    private long createdEpoch;

    @NotNull
    @Size(min = 1, max = 128)
    private String label;

    @NotNull
    @Size(min = 1)
    private String description;
}
Run Code Online (Sandbox Code Playgroud)

这是我的存储库:

@Repository
public interface AuditEventRepository extends PagingAndSortingRepository<AuditEventEntity, UUID> {
}
Run Code Online (Sandbox Code Playgroud)

当我为存储库编写以下单元测试时,即使“ label”字段为null,保存也会成功!

@DataJpaTest
@RunWith(SpringRunner.class)
public class AuditRepositoryTest {
    @Test
    public void shouldHaveLabel() {
        AuditEventEntity entity = AuditEventEntity.builder()
                .createdEpoch(Instant.now().toEpochMilli())
                .description(RandomStringUtils.random(1000))
                .build();
        assertThat(entity.getLabel()).isNullOrEmpty();
        AuditEventEntity saved = repository.save(entity);
        // Entity saved and didn't get validated!
        assertThat(saved.getLabel()).isNotNull();
        // The label field is still null, and the entity did persist.
    }

    @Autowired
    private AuditEventRepository repository;
}
Run Code Online (Sandbox Code Playgroud)

是使用列@NotNull还是使用列上的标志@Column(nullable = false)创建数据库not null

Hibernate: create table audit_log (id binary not null, created_epoch bigint not null, description varchar(255) not null, label varchar(128) not null, primary key (id))
Run Code Online (Sandbox Code Playgroud)

我认为验证器会自动工作。我在这里做错了什么?

dav*_*xxx 7

我以为验证器会自动工作。我在这里做错了什么?

您保存实体,但不刷新当前实体管理器的状态。
因此尚未执行实体的验证。

您可以参考Hibernate验证器常见问题解答

为什么当我调用 persist() 时我的 JPA 实体未验证?

为什么我致电时未验证我的 JPA 实体persist()EntityManager#flush()如果您希望触发验证,简短的答案是调用。

Hibernate ORM 和其他一些 ORM 尝试在访问数据库时批处理尽可能多的操作。实际的实体“持久”操作很可能仅在您调用flush()或事务提交时发生。

此外,了解哪个实体将被持久化取决于您的级联策略和对象图的状态。刷新是指 Hibernate ORM 识别所有已更改的实体并需要数据库操作(另请参阅 HHH-8028)。

因此使用JpaRepository.saveAndFlush()而不是JpaRepository.save()允许实体被验证。
或者在测试类中注入 anEntityManager或 an ,调用然后调用。TestEntityManagerJpaRepository.save()EntityManager/TestEntityManager.flush()

欲了解信息:

JpaRepository.save()调用 em.persist(entity)/em.merge(entity)
JpaRepository.saveAndFlush() 调用JpaRepository.save()然后 em.flush()


为了能够调用saveAndFlush(),您必须扩展您的存储库接口,JpaRepository例如:

public interface AuditEventRepository extends  JpaRepository<AuditEventEntity, UUID> {
Run Code Online (Sandbox Code Playgroud)

作为JpaRepository扩展PagingAndSortingRepository,此更改与您现有的声明保持一致。


我想补充一点,这个断言不是必需的:

assertThat(saved.getLabel()).isNotNull();
Run Code Online (Sandbox Code Playgroud)

您想要断言的是,它ValidationException被抛出,并且可能包含实际的错误消息。