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

Posted

技术标签:

【中文标题】如何为单元测试覆盖 insertable=false【英文标题】:How to override insertable=false for a unit test 【发布时间】:2018-07-31 13:40:20 【问题描述】:

我是我们应用程序中另一个系统的客人,我不想做出任何会产生大规模后果的更改。

我正在从头开始编写单元测试,因为之前的作者没有打扰。 (抱怨。)我正在尝试插入一行以使用 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;

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

我在删除 insertable 时没有什么大问题,因为它不是自动生成的,所以如果你要插入一条记录,为什么你不想包含它,这显然不会在系统内部发生。并且可更新将保护它。但如果我不需要,我真的不想。

所以,我的问题是,有没有办法只为单元测试覆盖它。我试着用谷歌搜索了几件事,但措辞有点问题,我没有找到任何东西。

【问题讨论】:

所以你写的是集成测试而不是单元测试? @daniu 从一个角度来看。如何在没有查询引擎和数据的情况下测试查询? 你没有,使用引擎并没有错。然而,一旦你开始操作被测试的代码,这些测试就变得没有意义了。 @daniu 你没看错,但我有什么选择? 你的意思是,就像使用orm.xml? 【参考方案1】:

通常您可以重新定义测试包中的任何类,并且它将被加载而不是主类,因为它具有更高的优先级。类加载路径通常按以下顺序排列优先级:

    测试类(如果正在运行测试) 测试资源(如果正在运行测试) 主要类 主要资源 测试依赖 jars(如果正在运行测试) 主要依赖 jars

你可以这样检查:

// 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 读取覆盖的类,除非您的配置文件 persistence.xmlorm.xml 或测试资源中的任何内容。这可能是也可能不是,但是如果您需要在测试中进行单独的配置,那么它必须列出所有需要扫描的类。您不能依赖 <exclude-unlisted-classes>false</exclude-unlisted-classes> 条目,因为 Hibernate 的扫描器是深度感知的,并且在 Class-Path 层次结构中不会比它找到配置 XML 的级别更深入。

【讨论】:

【参考方案2】:

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

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

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

【讨论】:

以上是关于如何为单元测试覆盖 insertable=false的主要内容,如果未能解决你的问题,请参考以下文章

Azure DevOps:如何为不同的测试(.net core、angular)合并两个代码覆盖率报告

如何为 iOS 项目设置最低代码覆盖率阈值?

如何为基于 http 的集成测试生成覆盖率报告?

如何为@KafkaListener 编写单元测试?

如何为 Python socketserver 请求处理程序编写单元测试?

如何为 UserDefaults 编写单元测试