如何在 gradle 测试中启用有用的 NullPointerExceptions

2023-12-29

此问题已在 Gradle 6.6 中修复

原帖

我想插旗-XX:+ShowCodeDetailsInExceptionMessages启用有用的 NPE(https://openjdk.java.net/jeps/358 https://openjdk.java.net/jeps/358)在测试中

I tried

tasks.withType<Test> {
    jvmArgs("-XX:+ShowCodeDetailsInExceptionMessages")
    testLogging {
        setExceptionFormat("full") // Prints the message of the exception
    }
}

但NPE仍然没有任何消息。

这是我的java版本

java -version
openjdk version "14.0.1" 2020-04-14
OpenJDK Runtime Environment (build 14.0.1+7)
OpenJDK 64-Bit Server VM (build 14.0.1+7, mixed mode, sharing)

进行更多研究编辑

为了更准确地找出问题的根源,我做了更多的工作。我的结论是,它不是来自我的java,也不是来自测试框架,它只能是gradle的错误配置或错误。 这是我所做的:

我已经用这个 build.gradle.kts 设置了一个空的 gradle 项目

plugins {
    java
}
repositories {
    mavenCentral()
}
dependencies {
    testImplementation("junit:junit:4.13")
}
tasks.withType<Test> {
    jvmArgs("-XX:+ShowCodeDetailsInExceptionMessages") // Helpful NPEs not working :(
    testLogging {
        setExceptionFormat("full") // Prints exception messages
    }
}

并带有一个测试类(src/test/java/TestNPE.java)

import org.junit.*;

public class TestNPE {

    @Test
    public void true_npe() {
        Object o = null;
        o.toString();
    }

    @Test
    public void throw_npe() {
        throw new NullPointerException("My own message");
    }
}

So now

./gradlew test

> Task :test FAILED

TestNPE > throw_npe FAILED
    java.lang.NullPointerException: My own message
        at TestNPE.throw_npe(TestNPE.java:13)

TestNPE > true_npe FAILED
    java.lang.NullPointerException
        at TestNPE.true_npe(TestNPE.java:8)

2 tests completed, 2 failed

这意味着该框架不会对 NPE 执行任何特殊操作。

之后,我通过使用调试日志运行测试来检索 gradle 使用的类路径。这样,我就可以直接运行 JUnit 了。使用 -XX:+ShowCodeDetailsInExceptionMessages 会显示有用的 NPE 消息:

java -cp '/Users/apflieger/src/gradle-helpfull-npe/build/classes/java/test:/Users/apflieger/.gradle/caches/modules-2/files-2.1/junit/junit/4.13/e49ccba652b735c93bd6e6f59760d8254cf597dd/junit-4.13.jar:/Users/apflieger/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar' -XX:+ShowCodeDetailsInExceptionMessages org.junit.runner.JUnitCore TestNPE
JUnit version 4.13
.E.E
Time: 0.006
There were 2 failures:
1) throw_npe(TestNPE)
java.lang.NullPointerException: My own message
    at TestNPE.throw_npe(TestNPE.java:13)
2) true_npe(TestNPE)
java.lang.NullPointerException: Cannot invoke "Object.toString()" because "o" is null
    at TestNPE.true_npe(TestNPE.java:8)

FAILURES!!!
Tests run: 2,  Failures: 2

这是一个 gradle 问题,它将从 gradle 6.6 开始工作。

你可以试试:

@Test
public void true_npe() {
    try {
        Object o = null;
        o.toString();
    } catch (Exception e) {
        e.printStackTrace();
        throw e;
    }
}

详细消息位于打印的堆栈跟踪中,但不在 junit 错误消息中

问题来自 gradle,我相信它使用对象输入/输出流将执行结果从测试虚拟机传递到 gradle 虚拟机。在此交换期间,来自原始 NPE 的扩展消息会丢失(是本机方法)。

您可以使用自定义 junit 5 扩展解决此问题(对于 junit 4 应该类似):

public class HelpfulNullPointerExceptionExtension implements TestExecutionExceptionHandler {
    @Override
    public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
        if (throwable instanceof NullPointerException) {
            NullPointerException extended = new NullPointerException(throwable.getMessage());
            extended.setStackTrace(throwable.getStackTrace());
            throw extended;
        }
        throw throwable;
    }
}

并自动在 META-INF/services/org.junit.jupiter.api.extension.Extension 文件中注册内容

org.mypackage.HelpfulNullPointerExceptionExtension 

或者,如果您关心嵌套 NPE:

public class HelpfulNullPointerExceptionExtension implements TestExecutionExceptionHandler {
@Override
public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
    Throwable actual = throwable;
    do {
        if (actual instanceof NullPointerException) {
            var field = Throwable.class.getDeclaredField("detailMessage");
            field.setAccessible(true);
            field.set(actual, actual.getMessage());
        }
        actual = actual.getCause();
    } while (actual != null && actual != throwable);
    throw throwable;
}

}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 gradle 测试中启用有用的 NullPointerExceptions 的相关文章

随机推荐

  • 如何使用spring data jpa连接从多个实体返回对象?

    我有三个实体 EntityA EntityB 和 EntityC 我需要使用 spring data jpa 从这些实体中将连接查询的值获取到对象列表中 查询是 select x id x formNo x name z testScore
  • 用约翰·梅杰的等式重写

    约翰 梅杰的等式带有以下重写引理 Check JMeq ind r JMeq ind r forall A Type x A P A gt Prop P x gt forall y A JMeq y x gt P y 很容易将其概括为 Le
  • 编码的 UI 测试_C#_manual_intervention

    我想通过键盘或鼠标交互来干预 C 中编码的 UI 测试的执行 例如 我想通过按 Tab 键暂停测试 并在再次按 Tab 键时继续测试 预先非常感谢您 由于您在评论中提到您想要暂停测试以便在计算机上执行其他操作 因此我同意 Coding Na
  • QueryOver API OrderBy 使用案例

    如何使用 QueryOver API 执行以下 LINQ to NHibernate 查询 这会从数据库中获取 Item 的所有记录的列表 并将状态为 Returned 的 Item 放置到列表的末尾 状态是一个枚举 映射到数据库中的 nv
  • 使用 jstl 获取明天的日期

    我尝试了以下方法来获取 JSTL 中明天的日期
  • 如何从文件系统加载任意 java .class 文件并对其进行反映?

    我想制作一个命令行实用程序 它根据外部类文件的反射执行一些操作 我将传递 class 文件或源文件的路径 可能是通配符 在执行过程中的某个时刻 我需要获取每个类的 Class 对象 而事先不知道它们的包名称 要做到这一点需要什么 我可以看什
  • 如何在 Blender 中将 IK 中的骨骼烘焙(转换)为 FK

    如何在 Blender 中将 IK 反向运动学 转换为 FK 正向运动学 我正在尝试将具有骨骼动画的模型导出到 THREE js 但是 它不支持 IK 因此 我需要将所有骨骼转换为FK 有谁知道有什么解决办法吗 谢谢 节日快乐 我发现 Ba
  • plot.lm():提取诊断 Q-Q 图中标记的数字

    对于下面的简单示例 您可以看到在随后的图中标识了某些点 如何提取这些图中识别的行号 尤其是正态 Q Q 图 set seed 2016 maya lt data frame rnorm 100 names maya 1 lt a maya
  • 删除 6 个月前的文件

    我想使用 Msbuild 删除文件夹中超过 6 个月前的文件 超过 6 个月的文件 我想使用 MsBuild 的 ModifiedTime 众所周知的项目元数据 我不喜欢使用自定义任务 只使用 msbuild 默认值和 Microsoft
  • Maven 寻找错误的原型包装

    我成功创建了一个原型 该原型在我公司的 Nexus 中引用 目录看起来结构良好 但是当我尝试从这个原型生成一个项目时 maven 将寻找一个 jar 并且我的原型被打包为 maven archetype 请参阅 下面的堆栈跟踪 INFO a
  • 使用python读取条形码

    我想用 python 读取条形码 我搜索了支持条形码读取并且也支持python 2 7的库 但我没有找到任何东西 有什么图书馆可以帮助我吗 另外 如果您知道有关条形码读取的任何教程 请告诉我在哪里可以找到 迟到总比不到好 Pyzbar ht
  • C# WPF DataGrid 不显示 SQLite 3 数据库中的小数

    我遇到了 C WPF 的问题 我想在 WPF DataGrid 控件中显示一些 SQLite 数据表 我们将产品的价格存储为 NUMERIC 但也尝试将其存储为 REAL 但效果完全相同 但在数据网格控件中 它显示为整数 尽管在 SQLit
  • libgdx 显示西里尔字母

    我在 libgdx 显示西里尔文时遇到以下问题 我举个例子 这有效 System out println 但它什么也没显示 field new TextField style 并尝试过但没有成功 try mmm new String t g
  • 自动隐藏 MenuStrip - 显示时如何激活它?

    I have a MenuStrip and I make it AutoHide using following code It hides shows prefect but when a control get focus by pr
  • 清理 Eclipse 索引,它与代码不同步

    我通过 Linux 上的链接资源使用带有 C 代码的 Eclipse 代码分析索引似乎已损坏 Goto 定义将光标置于定义附近 但不是定义上 刷新资源并不能解决此问题 重新启动 Eclipse 也不能解决此问题 有没有办法刷新索引并重建它
  • 当应用程序在后台被终止并且设备被锁定时,警报管理器将无法工作

    我已经陷入这样的境地很久了 我想使用警报管理器在特定时间显示通知 现在它可以在以下情况下使用 当应用程序在后台运行时 无论设备是否锁定 都会在正确的时间显示通知 应用程序在后台被杀死后 当设备未锁定时 我仍然会收到正确的通知 但当设备锁定时
  • 将以 10 为基数的数字转换为以 3 为基数的数字

    如何使用 int converter int num 方法将基数 10 的数字转换为基数 3 的数字 import java util Scanner public class BaseConverter int answer int cv
  • 同步使用 xmlhttprequest 的情况

    人们可以简单地将许多同步请求封装为异步请求 例如 下面代码中的 func 参数可以按顺序包含多个同步请求 与使用 DOM 作为作用于数据的媒介相比 这应该为您提供更多的数据处理能力 还有其他方法吗 我已经有一段时间没有使用javaScrip
  • 我应该选择什么数据库?

    我使用winforms开发一个桌面应用程序 现在我打算使用SQL Server Express 但问题是 如果我使用SQL Server Express 那么安装很麻烦 我需要先安装SQL Server 然后安装我的自己的应用程序 然后我尝
  • 如何在 gradle 测试中启用有用的 NullPointerExceptions

    此问题已在 Gradle 6 6 中修复 原帖 我想插旗 XX ShowCodeDetailsInExceptionMessages启用有用的 NPE https openjdk java net jeps 358 https openjd