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

时间:2018-06-27 14:30:55

标签: java spring validation spring-boot spring-data

这是我的实体:

@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;
}

这是我的存储库:

@Repository
public interface AuditEventRepository extends PagingAndSortingRepository<AuditEventEntity, UUID> {
}

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

@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;
}

无论我使用@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))

我认为验证器将自动运行。我在这里做什么错了?

1 个答案:

答案 0 :(得分:3)

  

我认为验证器将自动运行。我在做什么   这里错了吗?

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

您可以参考Hibernate validator FAQ

  

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

     

为什么我在致电persist()时未验证我的JPA实体?短   如果您希望验证通过,请致电EntityManager#flush()   触发。

     

休眠ORM和其他一些ORM尝试批处理尽可能多的操作   访问数据库时可能出现的情况。实际的   实体“持续”操作仅在您调用flush()或当   交易提交。

     

此外,知道哪个实体将要保留取决于您   级联策略和对象图的状态。冲洗是什么时候   Hibernate ORM标识所有已更改的实体,并   需要数据库操作(另请参见HHH-8028)。

因此,使用JpaRepository.saveAndFlush()代替JpaRepository.save()来验证实体。
或者,在测试类中插入EntityManagerTestEntityManager,调用JpaRepository.save(),然后调用EntityManager/TestEntityManager.flush()

有关信息:

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


要能够调用saveAndFlush(),必须使您的Repository接口扩展JpaRepository,例如:

public interface AuditEventRepository extends  JpaRepository<AuditEventEntity, UUID> {

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


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

assertThat(saved.getLabel()).isNotNull();

您要声明的是抛出了ValidationException,并且可能包含实际的错误消息。