JaCoCo and missed coverage of private default constructor

Viewed 14055

I'd like to see an example to prevent JaCoCo to report private empty constructors as non-covered code in a Java class.

In the maven plugin configuration I have

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

Isn't there something similar for the constructor?

6 Answers

As 0.8.0 is not yet released, I created a hamcrest matcher that checks whether a class is an utility class and additionally calls the private constructor using reflection (for code coverage purpose only).

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;
        }
    }
}
Related