4

在一个简单的项目中,我喜欢测试 @NotNull 验证(以及其他一些自定义验证)。

因此,我编写了一些执行此操作的单元测试:@Test(expect=ValidationException.class

一个最小的 mavinized 示例来重现我在 github 上上传的问题:

@Id如果是生成的值,我认为它运行良好。但是如果@Id系统给出了,验证将被忽略。

此类将显示重现问题的最小设置:

两个实体(一个具有生成值,一个没有:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class GeneratedId {
    @Id
    @GeneratedValue
    private Long    id;

    @NotNull
    private String  content;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class GivenId {
    @Id
    private Long    id;

    @NotNull
    private String  content;
}

单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:/applicationContext.xml")
@Transactional
@ActiveProfiles("embedded")
public class MyEntityTest
{
    @Autowired GeneratedIdService   generatedIdService;

    @Autowired GivenIdService       givenIdService;

    // This test will pass
    @Test(expected = ValidationException.class)
    public void shouldNotAllowNullValues1()
    {
        this.generatedIdService.save(new GeneratedId());
    }

    // This test will fail
    @Test(expected = ValidationException.class)
    public void shouldNotAllowNullValues2()
    {
        this.givenIdService.save(new GivenId(1L, null));
    }
}

这是样板服务和存储库

public interface GeneratedIdRepository extends JpaRepository<GeneratedId, Long> {
}

public interface GivenIdRepository extends JpaRepository<GivenId, Long> {
}

@Service
public class GeneratedIdService {
    @Autowired GeneratedIdRepository    repository;

    public GeneratedId save(final GeneratedId entity) {
        return this.repository.save(entity);
    }
}

@Service
public class GivenIdService {
    @Autowired GivenIdRepository    repository;

    public GivenId save(final GivenId entity) {
        return this.repository.save(entity);
    }
}

目前我正在使用 Spring 3.1.4、Spring-Data 1.3.4、Hibernate 4.1.10 和 Hibernate-Validator 4.2.0。

有什么建议可以跳过验证吗?

编辑1:

我在两个实体上都尝试了没有lombok,但仍然出现错误。

4

2 回答 2

5

如果要强制持久性提供程序在事务提交或回滚EntityManager 之前saveAndFlush(…)刷新 ,则需要手动刷新它或在JpaRepository.

原因是在自动生成 ID 的情况下,持久性提供程序必须刷新才能将 ID 绑定到 Java 对象。在手动分配 ID 的情况下,根本不需要在比事务结束时更早的时间点刷新,因此持久性提供程序避免了数据库交互。

除了这些技术细节之外,我认为依赖持久性提供者进行这种验证无论如何在架构上都是有问题的。如果提供者检测到违规行为,您实际上已经通过各种业务逻辑管道传递了一个无效对象。为了确保您不必进行防御性编码(到处检查 null),您可以简单地通过检查传递给构造函数或 setter 的值来强制属性不可为空。这样,您基本上知道,无论何时获得对象的实例,该值永远不会是null,无论是否调用了某个第三个框架,或者某些开发人员不小心忘记了调用它。

于 2013-08-21T07:54:53.190 回答
2

强制刷新使验证有效:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:/applicationContext.xml")
@Transactional
@ActiveProfiles("embedded")
public class MyEntityTest
{

    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    GeneratedIdService  generatedIdService;

    @Autowired
    GivenIdService      givenIdService;

    // This test will pass
    @Test(expected = ValidationException.class)
    public void shouldNotAllowNullValues1()
    {
        this.generatedIdService.save(new GeneratedId());
    }

    // This test will fail
    @Test(expected = ValidationException.class)
    public void shouldNotAllowNullValues2()
    {
        this.givenIdService.save(new GivenId(1L, null));
        entityManager.flush();
    }
}

另见:这个问题

于 2013-08-16T18:35:37.067 回答