Groovy JUnit Ascept.assumeNotNull抛出Null指针,而不是跳过测试
我在groovy中有一个junit(使用JUnit4.12)测试,只有在getenv!=空值: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
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!"
}
但是当我运行测试时,它会打印:
itnull然后抛出一个null指针异常(在以下行中:assumeNotNull(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[]);