如何在Gradle测试中启用有用的NullPointerException [英] How to enable helpful NullPointerExceptions in gradle test

查看:333
本文介绍了如何在Gradle测试中启用有用的NullPointerException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想标记-XX:+ShowCodeDetailsInExceptionMessages以启用有用的NPE( https://openjdk.java .net/jeps/358 )

I want to put the flag -XX:+ShowCodeDetailsInExceptionMessages to enable helpful NPEs (https://openjdk.java.net/jeps/358) on the tests

我尝试过

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

但是NPE仍然没有消息.

But the NPEs have still no messages.

这是我的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的错误配置或错误. 这是我所做的:

To find out more precisely the origin of the problem, I did some more work. My conclusion is that it doesn't come from my java nor the test framework, it can only be a misconfig of gradle or a bug. Here's what i've done :

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

I've setup an empty gradle project with this build.gradle.kts

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)

And with a test class (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并没有做任何特别的事情.

This means the framework doesn't do anything special with NPEs.

在那之后,我通过运行带有调试日志的test来检索classpath gradle的用法.这样,我可以直接运行JUnit.使用-XX:+ ShowCodeDetailsInExceptionMessages会显示有用的NPE消息:

After that, I retrieved the classpath gradle uses by running test with debug logs. With that, I could run JUnit directly. With -XX:+ShowCodeDetailsInExceptionMessages the helpful NPE message shows up :

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开始运行.

This is a gradle problem, it will be working from gradle 6.6.

您可以尝试:

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

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

The detailed message is in the printed stack trace but it's not in the junit error message

问题出在gradle上,我相信它正在使用对象输入/输出流将执行结果从测试vm传递到gradle vm.在此交换过程中,原始NPE的扩展消息将丢失(这是一种本机方法).

The problem is from gradle, I believe it's using Object Input/Output Stream to pass execution results from test vm to gradle vm. During this exchange the extended message from the original NPE is lost (is a native method).

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

You can workaround this with a custom junit 5 extension (should be similar for 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文件中注册

And register automatically in a META-INF/services/org.junit.jupiter.api.extension.Extension file with content

org.mypackage.HelpfulNullPointerExceptionExtension 

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

Or, if you care about nested 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;
}

}

这篇关于如何在Gradle测试中启用有用的NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆