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

标签 java gradle gradle-kotlin-dsl java-14

此问题已在 Gradle 6.6 中得到修复
原帖
我要挂旗-XX:+ShowCodeDetailsInExceptionMessages在测试中启用有用的 NPE ( https://openjdk.java.net/jeps/358 )
我试过

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");
    }
}
所以现在
./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,我相信它使用对象输入/输出流将执行结果从测试 vm 传递到 gradle vm。在此交换期间,来自原始 NPE 的扩展消息丢失(是 native 方法)。
您可以使用自定义 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;
}
}

关于java - 如何在 gradle 测试中启用有用的 NullPointerExceptions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61664979/

相关文章:

java - 将 DOM 节点作为 Any 对象添加到 JAXB 类

java - 无法理解泛型和继承

java - 如何解决在 OC4J (10.1.3.5) 中加载 Web 应用程序时出现错误并提示“找不到类 oracle.jbo.JboException”的问题?

android - 在 Android Studio 中包含依赖项会产生 UnsatisfiedLinkError

Android 支持库构建 v26.X.X 构建错误 : Attribute "font" already defined

java - 不断收到错误插入变量声明以在我的Java程序上完成VariableDeclaration

android - 如何在构建过程中从Android库项目aar Artifact 中排除库jar?

gradle - 在Gradle中,有没有更好的方法来获取环境变量?

gradle - Gradle:从根项目任务中的子项目中读取变量 block

kotlin - 在 build.gradle.kts 中设置环境变量