如何为单元测试覆盖insertable = false

时间:2018-07-31 13:40:20

标签: java hibernate jpa

我是我们应用程序中另一个系统上的客人,并且我不想进行任何大规模的更改。

由于先前的作者没有打扰,因此我正在从头开始编写单元测试。 (抱怨)。我试图插入一行以用JPA / hibernate测试我的查询,但很惊讶我得到以下错误:

javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: integrity constraint violation: NOT NULL check constraint; SYS_CT_14316 table: OPTIONVALUE column: OPTION_INDEX

    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1306)
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:989)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:293)
    at com.sun.proxy.$Proxy109.flush(Unknown Source)

尤其是当我知道我已经设置了值时,因为必须为此写一个setter。然后,在其中一个对象上,找到以下定义(必须查找):

public static final String OPTION_VALUE_POSITION_COLUMN = "option_index";
@Column(name = OPTION_VALUE_POSITION_COLUMN, insertable = false, updatable = false, nullable = false)
private int position;

所以这解释了为什么我在该列上仍然为空。

在删除可插入内容方面我没有很大的问题,因为它不是自动生成的,所以如果您要插入一条记录(显然在系统内部从未发生过),为什么不愿意包含它。并且可更新将保护它。但是我真的不想,如果不需要的话。

所以,我的问题是,有没有一种方法可以仅针对单元测试来覆盖它。我尝试使用Google搜索一些内容,但是对此措辞有点问题,但是我什么也没找到。

2 个答案:

答案 0 :(得分:0)

通常,您可以在Test程序包中重新定义任何类,由于它具有更高的优先级,因此它将代替主类被加载。通常按以下顺序对类加载路径进行优先级排序:

  1. 测试类(如果正在运行测试)
  2. 测试资源(如果正在运行测试)
  3. 主要课程
  4. 主要资源
  5. 测试依赖罐(如果正在运行测试)
  6. 主要依赖罐

您可以按照以下方式进行检查:

// I have yet to run into a custom ClassLoader that does not extend URLClassLoader
URLClassLoader urls = (URLClassLoader) getClass().getClassLoader();
for (URL url : urls.getURLs()) {
    System.out.println(url);
}

但是,这里有点问题。除非您拥有配置文件persistence.xmlorm.xml或测试资源中的任何内容,否则Hibernate的ClassLoader可能(也可能不会)从Test中读取覆盖的类。可能会,也可能不是,但如果您需要在测试中进行单独的配置,则它必须列出所有需要扫描的类。您不能依靠<exclude-unlisted-classes>false</exclude-unlisted-classes>条目,因为Hibernate的扫描器是可感知深度的,并且在Class-Path层次结构中的深度不比它发现配置XML的层次深。

答案 1 :(得分:0)

我不知道这是否是最好的解决方案,但在某些情况下它可能是一种合法的解决方法。

在这些情况下,我使用原始查询来插入/更新我的实体:

Query query = entityManager.createNativeQuery("insert into MY_TABLE " + 
            "(ID, NAME) values (1, 'user1')");
query.executeUpdate();