cobertura 未能通过反射测试 class
cobertura fails tests for class with reflection
我 运行 mvn clean cobertura:cobertura install
在我的项目上,但其中一个测试失败了。
测试尝试使用 反射 编写的构建器访问 class。
public MyClass(Builder builder) throws Exception {
Field[] classFields = MyClass.class.getDeclaredFields();
Field[] classBuilderFields = Builder.class.getDeclaredFields();
for (int i = 0; i < classBuilderFields.length; i++) {
Field fieldInClass = classFields[i];
Field fieldInBuilder = classBuilderFields[i];
fieldInBuilder.setAccessible(true);
String fieldNameInClass = fieldInClass.getName();
String fieldNameInBuilder = fieldInBuilder.getName();
if (null != fieldNameInClass && null != fieldNameInBuilder && fieldNameInClass.equals(fieldNameInBuilder)) {
fieldInClass.set(this, fieldInBuilder.get(builder));
} else {
throw new Exception("");
}
}
}
我调试了代码,发现 cobertura "implents" 在我的 class __cobertura_counters 中有一个自己的变量。这是例外情况:
java.lang.IllegalAccessException: Can not set static final [I field com.domain.MyClass.__cobertura_counters to
at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:73)
at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:77)
at sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:77)
at java.lang.reflect.Field.set(Field.java:741)
at com.domain.MyClass.<init>(MyClass.java:217)
at com.domain.MyClassTest.setUp(MyClassTest.java:57)
at com.domain.MyClass$Builder.build(MyClass.java:197)
我该如何解决这个问题?
问题是,您尝试修改的字段是最终字段。可以删除 final 修饰符,并且可以做到。 polygenelubricants 发布了一段很好的代码,您可以使用它来删除修饰符。您可以在这里找到它:Using reflection to change static final File.separatorChar for unit testing?
是的,Cobertura 添加此字段是为了跟踪访问了哪些代码。出于类似的目的,其他代码覆盖工具添加了类似的字段。生成的字段具有此签名:
public static final transient int[] __cobertura_counters;
您可以做的只是忽略代码中的瞬态字段。你可以这样做:
if (!Modifier.isTransient(fieldInClass.getModifiers())) {
// do a thing
}
但是请注意,non-generated 代码也可以有瞬态字段,因此根据您要反映的代码,这可能是也可能不是一个选项。否则,您唯一的选择(AFAIK)就是简单地检查是否 fieldInClass.getName().equals("__cobertura_counters")
.
通常情况下,编译器生成的字段会被标记为"synthetic"。例如,javac 为 non-static 内部 类 生成的 this[=13=]
字段是合成的。很容易检查:fieldInClass.isSynthetic()
。但是,出于某种原因,Cobertura 不遵循此约定。
我 运行 mvn clean cobertura:cobertura install
在我的项目上,但其中一个测试失败了。
测试尝试使用 反射 编写的构建器访问 class。
public MyClass(Builder builder) throws Exception {
Field[] classFields = MyClass.class.getDeclaredFields();
Field[] classBuilderFields = Builder.class.getDeclaredFields();
for (int i = 0; i < classBuilderFields.length; i++) {
Field fieldInClass = classFields[i];
Field fieldInBuilder = classBuilderFields[i];
fieldInBuilder.setAccessible(true);
String fieldNameInClass = fieldInClass.getName();
String fieldNameInBuilder = fieldInBuilder.getName();
if (null != fieldNameInClass && null != fieldNameInBuilder && fieldNameInClass.equals(fieldNameInBuilder)) {
fieldInClass.set(this, fieldInBuilder.get(builder));
} else {
throw new Exception("");
}
}
}
我调试了代码,发现 cobertura "implents" 在我的 class __cobertura_counters 中有一个自己的变量。这是例外情况:
java.lang.IllegalAccessException: Can not set static final [I field com.domain.MyClass.__cobertura_counters to
at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:73)
at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:77)
at sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:77)
at java.lang.reflect.Field.set(Field.java:741)
at com.domain.MyClass.<init>(MyClass.java:217)
at com.domain.MyClassTest.setUp(MyClassTest.java:57)
at com.domain.MyClass$Builder.build(MyClass.java:197)
我该如何解决这个问题?
问题是,您尝试修改的字段是最终字段。可以删除 final 修饰符,并且可以做到。 polygenelubricants 发布了一段很好的代码,您可以使用它来删除修饰符。您可以在这里找到它:Using reflection to change static final File.separatorChar for unit testing?
是的,Cobertura 添加此字段是为了跟踪访问了哪些代码。出于类似的目的,其他代码覆盖工具添加了类似的字段。生成的字段具有此签名:
public static final transient int[] __cobertura_counters;
您可以做的只是忽略代码中的瞬态字段。你可以这样做:
if (!Modifier.isTransient(fieldInClass.getModifiers())) {
// do a thing
}
但是请注意,non-generated 代码也可以有瞬态字段,因此根据您要反映的代码,这可能是也可能不是一个选项。否则,您唯一的选择(AFAIK)就是简单地检查是否 fieldInClass.getName().equals("__cobertura_counters")
.
通常情况下,编译器生成的字段会被标记为"synthetic"。例如,javac 为 non-static 内部 类 生成的 this[=13=]
字段是合成的。很容易检查:fieldInClass.isSynthetic()
。但是,出于某种原因,Cobertura 不遵循此约定。