Groovy JUnit Ascept.assumeNotNull抛出Null指针,而不是跳过测试

Groovy JUnit Ascept.assumeNotNull抛出Null指针,而不是跳过测试,groovy,junit,Groovy,Junit,我在groovy中有一个junit(使用JUnit4.12)测试,只有在getenv!=空值: import org.junit.Assume import org.junit.Before import org.junit.Ignore import org.junit.Test ... @Test public void skipWhenNull() throws Exception { def getenv = Sys

我在groovy中有一个junit(使用JUnit4.12)测试,只有在getenv!=空值

    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!"
    }

但是当我运行测试时,它会打印:
itnullassumeNotNull(getenv);
)。问题的关键是:
假设.assumeNotNull(expr)
expr
的计算结果为null而不是抛出null指针时,它不会跳过测试?

我认为这可能是一个bug,但我认为这是Groovy的动态类型系统在其默认行为中的结果<代码>假设.assumeNotNull(对象…对象)
方法使用varargs参数。这意味着在传递非数组元素的情况下,编译器会将其包装在预期类型的数组中

String getenv=System.getenv(“bogos”);
假设.assumeNotNull(getenv);//-->assumeNotNull(新对象[]{getenv});
这就是Java的静态编译器所做的。因此,在
getenv==null
的情况下,我们得到:

aspect.assumeNotNull(新对象[]{null});
包含单个null元素的非空数组。另一方面,如果我们使用数组类型指定一个变量,并为其分配一个
null
值,则调用相同的方法将导致
NullPointerException
,如下例所示:

String[]数组=null;
假设.assumeNotNull(数组);//-->投掷NPE
这至少是Java中发生的事情。现在,为什么它在Groovy单元测试中失败?Groovy在默认情况下是一种动态类型的语言,因此它在这方面的行为非常不同。Groovy的类型系统似乎将
null
值应用于方法类型,而不将其包装在数组中,因此在将
null
传递给期望对象(例如
对象)的方法时。。。对象
我们总是得到
objects==null
而不是
objects==newobject[]{null}

我开始问自己这是不是一个bug。从一个角度来看,我希望动态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
或者,您可以更明确地调用
aspect.assumeNotNull
方法。如果更换:

Assume.assumeNotNull(getenv);
与:


然后,您将使用
Object[]
数组显式地包装参数,并且您将阻止传递由
null
表示的数组对象,而是传递包含
null
值的单个元素数组。

assumeNotNull
获得
null
值时,它应该停止并忽略测试。您可能会仔细检查您的导入,可能会得到其他具有相同类/方法的库。假设你正在打印“它是空的”。。。这是正确的吗?另外,NPE是否从断言行抛出?是的,请参阅我更新的帖子您使用的JUnit版本是什么?我使用的是版本4.12
Assume.assumeNotNull([getenv] as Object[]);