【问题标题】:JaCoCo and missed coverage of private default constructorJaCoCo 和未涵盖的私有默认构造函数
【发布时间】:2016-06-27 06:20:54
【问题描述】:

我希望看到一个示例,以防止 JaCoCo 将私有空构造函数报告为 Java 类中的未覆盖代码。

在我的 maven 插件配置中

   <rule>
     <element>CLASS</element>
       <excludes>
         <exclude>JAVAC.SYNTHCLASS</exclude>
         <exclude>JAVAC.SYNTHMETH</exclude>
       </excludes>
     </element>
   </rule>

构造函数没有类似的东西吗?

【问题讨论】:

    标签: java code-coverage jacoco-maven-plugin private-constructor


    【解决方案1】:

    不支持。 official documentation 说:

    过滤测试执行在设计上存在问题或不可能的代码

    • 私有的空默认构造函数 - 假设没有调用它
    • 普通的 getter 和 setter
    • 抛出 AssertionErrors 的块 - 如果出现条件(如果 !assertion throw new AssertionError),则应忽略整个块

    另见:https://github.com/jacoco/jacoco/issues/298

    更新:此问题已在 https://github.com/jacoco/jacoco/pull/529 中修复,应在 0.8.0 中。

    【讨论】:

      【解决方案2】:

      无法关闭该选项。如果您迫切需要满足与覆盖率相关的一些质量标准,您始终可以使用一种变通方法并通过反射调用这些私有构造函数。

      【讨论】:

        【解决方案3】:

        对于这个用例,反射是完全可以接受的,很少有众所周知的类。下面的代码可以与基于名称的自动类别检测一起使用。对于带有附加断言的示例“.*Factory”类。

        @Test
        public void testCoverage()
            throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
            coverageSingleton(MySingleton1.class);
            coverageSingleton(MySingleton2.class);
        }
        
        private <S> void coverageSingleton(Class<S> singletonClass)
            throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
            final Constructor<S> constructor = singletonClass.getDeclaredConstructor();
            constructor.setAccessible(true);
            constructor.newInstance();
        }
        

        【讨论】:

        【解决方案4】:

        根据官方文档,它将与0.8.0一起发布

        过滤测试执行有问题或不可能的代码 设计

        没有参数的私有空构造函数 - Done

        您可以找到详细信息here

        【讨论】:

          【解决方案5】:

          这并没有解决空私有构造函数不需要覆盖的基本问题,而是要让 JaCoCo 真正报告空私有构造函数的覆盖率,您需要调用它。你是怎样做的?您在静态初始化块中调用它。

          public class MyClass {
             static {
                new MyClass();
             }
             private MyClass(){}
          }
          

          编辑: 原来,不能保证要执行的静态初始化块。因此,我们仅限于使用以下方法:

          static <T> void callPrivateConstructorIfPresent(Class<T> clazz){
                  try{
                      Constructor<T> noArgsConstructor = clazz.getDeclaredConstructor();
                      if(!noArgsConstructor.isAccessible()){
                          noArgsConstructor.setAccessible(true);
                          try {
                              noArgsConstructor.newInstance();
                          } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) 
                          {
                              e.printStackTrace();
                          }
                          noArgsConstructor.setAccessible(false);
                      }
                  } catch(NoSuchMethodException e){}
              }
          

          【讨论】:

            【解决方案6】:

            由于 0.8.0 尚未发布,我创建了一个 hamcrest 匹配器,用于检查一个类是否是一个实用程序类,并额外使用反射调用私有构造函数(仅用于代码覆盖目的)。

            https://github.com/piotrpolak/android-http-server/blob/master/http/src/test/java/ro/polak/http/utilities/IOUtilitiesTest.java

            package ro.polak.http.utilities;
            
            import org.junit.Test;
            
            
            import static org.hamcrest.core.Is.is;
            import static org.junit.Assert.assertThat;
            import static ro.polak.http.ExtraMarchers.utilityClass;
            
            public class IOUtilitiesTest {
            
                @Test
                public void shouldNotBeInstantiable() {
                    assertThat(IOUtilities.class, is(utilityClass()));
                }
            }
            

            https://github.com/piotrpolak/android-http-server/blob/master/http/src/test/java/ro/polak/http/ExtraMarchers.java

            package ro.polak.http;
            
            import org.hamcrest.Description;
            import org.hamcrest.Matcher;
            import org.hamcrest.TypeSafeMatcher;
            
            import java.lang.reflect.Constructor;
            import java.lang.reflect.InvocationTargetException;
            
            public class ExtraMarchers {
            
                private static final UtilClassMatcher utilClassMatcher = new UtilClassMatcher();
            
                public static Matcher<? super Class<?>> utilityClass() {
                    return utilClassMatcher;
                }
            
                private static class UtilClassMatcher extends TypeSafeMatcher<Class<?>> {
                    @Override
                    protected boolean matchesSafely(Class<?> clazz) {
                        boolean isUtilityClass = false;
                        try {
                            isUtilityClass = isUtilityClass(clazz);
                        } catch (ClassNotFoundException | InstantiationException e) {
                            // Swallowed
                        }
            
                        // This code will attempt to call empty constructor to generate code coverage
                        if (isUtilityClass) {
                            callPrivateConstructor(clazz);
                        }
            
                        return isUtilityClass;
                    }
            
                    @Override
                    protected void describeMismatchSafely(Class<?> clazz, Description mismatchDescription) {
                        if (clazz == null) {
                            super.describeMismatch(clazz, mismatchDescription);
                        } else {
                            mismatchDescription.appendText("The class " + clazz.getCanonicalName() + " is not an utility class.");
            
                            boolean isNonUtilityClass = true;
                            try {
                                isNonUtilityClass = !isUtilityClass(clazz);
                            } catch (ClassNotFoundException e) {
                                mismatchDescription.appendText(" The class is not found. " + e);
                            } catch (InstantiationException e) {
                                mismatchDescription.appendText(" The class can not be instantiated. " + e);
                            }
            
                            if (isNonUtilityClass) {
                                mismatchDescription.appendText(" The class should not be instantiable.");
                            }
                        }
                    }
            
                    @Override
                    public void describeTo(Description description) {
            
                    }
            
                    private void callPrivateConstructor(Class clazz) {
                        try {
                            Constructor<?> constructor = clazz.getDeclaredConstructor();
                            constructor.setAccessible(true);
                            constructor.newInstance();
                        } catch (NoSuchMethodException | IllegalAccessException |
                                InstantiationException | InvocationTargetException e) {
                            // Swallowed
                        }
                    }
            
                    private boolean isUtilityClass(Class clazz) throws ClassNotFoundException, InstantiationException {
                        boolean hasPrivateConstructor = false;
                        try {
                            clazz.newInstance();
                        } catch (IllegalAccessException e) {
                            hasPrivateConstructor = true;
                        }
                        return hasPrivateConstructor;
                    }
                }
            }
            

            【讨论】:

              猜你喜欢
              • 2017-08-30
              • 2018-11-25
              • 1970-01-01
              • 2020-05-19
              • 2015-04-20
              • 2013-02-08
              • 2023-03-20
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多