【问题标题】:cobertura fails tests for class with reflectioncobertura 未能通过反射类测试
【发布时间】:2015-12-01 10:36:03
【问题描述】:

我在我的项目上运行mvn clean cobertura:cobertura install,但其中一项测试失败了。

测试尝试使用 reflection 编写的构建器访问类。

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 在我的类 __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)

我该如何解决这个问题?

【问题讨论】:

    标签: java maven cobertura


    【解决方案1】:

    确实,Cobertura 添加了此字段,以便跟踪哪些代码已被访问。其他代码覆盖工具添加了类似的字段,用于类似的目的。生成的字段具有以下签名:

    public static final transient int[] __cobertura_counters;
    

    您可以做的就是忽略代码中的瞬态字段。你可以这样做:

    if (!Modifier.isTransient(fieldInClass.getModifiers())) {
        // do a thing
    }
    

    但是请注意,非生成代码也可能具有瞬态字段,因此根据您要反映的代码,这可能是也可能不是一个选项。否则,您唯一的选择 (AFAIK) 是简单地检查 fieldInClass.getName().equals("__cobertura_counters") 是否。

    通常,编译器生成的字段会被标记为“合成”。例如,javac 为非静态内部类生成的this$0 字段是合成的。很容易检查:fieldInClass.isSynthetic()。但是,出于某种原因,Cobertura 不遵循此约定。

    【讨论】:

      【解决方案2】:

      问题是,您尝试修改的字段是最终字段。可以去掉final修饰符,也可以做到。 polygenelubricants 发布了一段很好的代码,您可以使用它来删除修饰符。你可以在这里找到它:Using reflection to change static final File.separatorChar for unit testing?

      【讨论】:

      • 最后一个试图修改的静态变量是 cobertura 的变量,不是我的。它以某种方式将其 var 注入我的班级
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 2021-10-22
      • 1970-01-01
      • 1970-01-01
      • 2015-03-03
      • 1970-01-01
      相关资源
      最近更新 更多