JaCoCo and missing default private constructor scope

I would like to see an example to prevent JaCoCo from reporting private empty constructors as unclosed 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> 

Is there something similar for the constructor?

+5
source share
6 answers

This is not supported. The official documentation reads:

Filters for code in which test execution is questionable or impossible by design

  • Private empty constructors by default - in the absence of calls to it
  • Normal getters and setters
  • Blocks that throw AssertionErrors - the entire block should be ignored if the condition (if! Assertion throw new AssertionError)

see also: https://github.com/jacoco/jacoco/issues/298

Update:. This has been fixed at https://github.com/jacoco/jacoco/pull/529 and should be at 0.8.0.

+8
source

Unable to disable this option. If you desperately need to meet some kind of quality gate related to the coating, you can always use the workaround and call these private designers through reflection.

+1
source

Reflection is quite acceptable for this use case; there are several well-known classes. The following code can be used with automatic class detection based on the name. For classes ". * Factory" with additional statements.

 @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(); } 
0
source

According to official documentation, it will be released using 0.8.0

Filters for code in which test execution is doubtful or impossible using Design

Private empty constructors that have no arguments - Done

Here you can find here .

0
source

Since 0.8.0 has not yet been released, I created a hamcrest match, which checks if the class is a utility class, and additionally calls a private constructor using reflection (only for code coverage purposes).

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; } } } 
0
source

This does not solve the significant problem when empty private constructors do not need coverage, but in order to draw a JaCoCo report on an empty private constructor, you need to call it. How do you do this? You call it in a static initialization block.

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

EDIT: It turned out that there is no guarantee that a static initialization block will execute. Thus, we restrict ourselves to using methods as follows:

 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){} } 
-1
source

Source: https://habr.com/ru/post/1244918/


All Articles