如何在单元测试中覆盖 insertable=false?

3
我是我们应用程序中另一个系统上的一位客人,我不想做出任何具有大规模影响的更改。
我正在从头开始编写单元测试,因为之前的作者没有关注。 (咕哝。)我试图使用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;

这就解释了为什么我在那一列上仍然得到null。
我并不是非常介意删除insertable,因为它不是自动生成的,所以如果您要插入记录,为什么不包括它呢?但是updatable将保护它。但是如果没有必要,我真的不想这样做。
所以,我的问题是,是否有一种方法可以仅针对单元测试覆盖此项。我尝试了谷歌搜索一些东西,但是这个短语的措辞有点棘手,我没有找到任何东西。

那么你是在编写集成测试而不是单元测试? - daniu
从一个角度来看,如果没有查询引擎和数据,你如何测试一个查询? - Thom
@daniu 你说得没错,但我的选择是什么? - Thom
@BillyFrost 以什么方式? - Thom
你的意思是我可以在测试资源或其他类似的地方使用它吗? - Thom
显示剩余3条评论
2个回答

1
通常情况下,您可以重新定义Test包中的任何类,并且它将被加载代替主类,因为它具有更高的优先级。类加载路径通常按以下顺序优先考虑:
  1. 测试类(如果正在运行测试)
  2. 测试资源(如果正在运行测试)
  3. 主要类
  4. 主要资源
  5. 测试依赖项JAR(如果正在运行测试)
  6. 主要依赖项JAR
您可以像这样检查它:
// 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);
}

这里有一个问题,Hibernate的ClassLoader可能(也可能不)从Test中读取覆盖的类,除非你在Test Resources中有你的配置文件、或其他文件。这可能是或可能不是这种情况,但如果你需要在测试中有一个单独的配置,那么它必须列出所有需要被扫描的类。你不能依赖于false条目,因为Hibernate的扫描器具有深度感知能力,并且不会在Class-Path层次结构中深入到它发现配置XML的级别以下。

0

我不确定这是否是最佳解决方案,但在某些情况下它可以是一个合法的解决方法。

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接