JUnit Assume.assumeNotNull выбрасывает нулевой указатель вместо пропуска теста - PullRequest
0 голосов
/ 06 декабря 2018

У меня есть этот тест junit (с использованием JUnit 4.12) в groovy, который должен выполняться только, если getenv! = Null :

    import org.junit.Assume
    import org.junit.Before
    import org.junit.Ignore
    import org.junit.Test
    ...
    @Test
    public void skipWhenNull() throws Exception {
        def getenv = System.getenv("bogos")
        if( getenv == null) {
            println "Its null!"
        }
        Assume.assumeNotNull(getenv);
        println "Test executing!"
    }

Но когда я запускаю тест, он печатает:Its null! и затем генерирует исключение NullPointer (в строке: Assume.assumeNotNull(getenv);).Не является ли смысл: Assume.assumeNotNull(expr) не в том, что он пропустит тест, когда expr оценивается как ноль вместо бросания нулевого указателя?

1 Ответ

0 голосов
/ 06 декабря 2018

Я думал, что это может быть ошибкой, но я думаю, что это скорее следствие динамической системы типов Groovy в ее поведении по умолчанию.Assume.assumeNotNull(Object... objects) метод использует параметры varargs.Это означает, что в случае передачи не-массивного элемента компилятор оборачивает его в массив ожидаемого типа.

String getenv = System.getenv("bogos"); 

Assume.assumeNotNull(getenv); // --> Assume.assumeNotNull(new Object[] { getenv });

Это то, что делает статический компилятор Java.Таким образом, в случае getenv == null мы получаем:

Assume.assumeNotNull(new Object[] { null });

Непустой массив, который содержит один нулевой элемент.С другой стороны, если мы укажем переменную с типом массива и присвоим ей значение null, вызов этого же метода вызовет NullPointerException, как в следующем примере:

String[] array = null;

Assume.assumeNotNull(array); // --> throws NPE

Это, по крайней мере, то, что происходит в Java.Теперь, почему это не проходит в модульном тесте Groovy?Groovy по умолчанию является динамически типизированным языком, поэтому в этой области он ведет себя совершенно иначе.Похоже, что система типов Groovy применяет значение null к типу метода, не заключая его в массив, поэтому в случае передачи null методу, который ожидает, например, Object... objects, мы всегда получаем objects == null вместо objects == new Object[] { null }.

Я начал задавать себе вопрос, это ошибка или нет.С одной стороны, я ожидаю, что динамический Groovy будет вести себя так же, как статически скомпилированный код.Но, с другой стороны, в динамически типизированной системе это различие допустимо (и, возможно, даже желательно), потому что динамическая система типов выводит тип во время выполнения.Он видит null, поэтому думает, что мы намереваемся присвоить null значение переменной типа Object[].

Решение

Существует два способа решения этой проблемы.

1.Включите статическую компиляцию

Если вы не используете динамические и метапрограммирующие функции Groovy в своем тестовом примере, вы можете легко аннотировать его аннотацией @groovy.transform.CompileStatic, чтобы сгенерировать байт-код, который больше похож на байт-код Java.Например, вот как выглядит байт-код вашего метода в динамическом Groovy:

@Test
public void skipWhenNull() throws Exception {
    CallSite[] var1 = $getCallSiteArray();
    Object getenv = var1[4].call(System.class, "bogos");
    if (ScriptBytecodeAdapter.compareEqual(getenv, (Object)null)) {
        var1[5].callCurrent(this, "Its null!");
    }

    var1[6].call(Assume.class, getenv);
    var1[7].callCurrent(this, "Test executing!");
}

А вот тот же метод, но помеченный @CompileStatic с точки зрения байт-кода:

@Test
public void skipWhenNull() throws Exception {
    String getenv = System.getenv("bogos");
    Object var10000;
    if (getenv == null) {
        DefaultGroovyMethods.println(this, "Its null!");
        var10000 = null;
    }

    Assume.assumeNotNull(new Object[]{getenv});
    var10000 = null;
    DefaultGroovyMethods.println(this, "Test executing!");
    var10000 = null;
}

2.Оберните getenv массивом

В качестве альтернативы, вы можете сделать более явный вызов метода Assume.assumeNotNull.Если вы замените:

Assume.assumeNotNull(getenv);

на:

Assume.assumeNotNull([getenv] as Object[]);

, тогда вы явным образом перенесете параметр в массив Object[] и не допустите передачу объекта массива, представленного null, но вместо этого один массив элементов, содержащий null значение.

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