Как включить полезные исключения NullPointerExceptions в тесте Gradle - PullRequest
7 голосов
/ 07 мая 2020

Я хочу установить флаг -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 или ошибка. Вот что я сделал:

Я установил пустой проект gradle с этим 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)

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.

После этого я получил classpath 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

1 Ответ

0 голосов
/ 11 мая 2020

Это проблема 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 теряется (это собственный метод).

Вы можете обойти это с помощью специального расширения 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;
}

}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...