Reputation: 13666
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?
Upvotes: 14
Views: 17353
Reputation: 2354
If you are using Lombok, the easiest way is to annotate the constructor with @Generated
, so JaCoCo will ignore this constructor.
import lombok.Generated;
public class MyClass {
@Generated
private MyClass(){}
}
Upvotes: 0
Reputation: 497
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).
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()));
}
}
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;
}
}
}
Upvotes: -1
Reputation: 63
This is not solving the essential problem that empty private constructors should not need coverage, but to actually make JaCoCo report coverage on an empty private constructor you need to call it. How do you do that? You call it in the static initialization block.
public class MyClass {
static {
new MyClass();
}
private MyClass(){}
}
EDIT: Turned out that there is no guarantee on the static initialization block to be executed. Thus we are limited to using methods as this one:
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){}
}
Upvotes: -1
Reputation: 1759
This is not supported. The official documentation says:
Filters for Code where Test Execution is Questionable or Impossible by Design
- Private, empty default constructors - assuming no calls to it
- Plain getters and setters
- Blocks that throw AssertionErrors - Entire block should be ignored if a condition (if !assertion throw new AssertionError)
see also : https://github.com/jacoco/jacoco/issues/298
Update: This was fixed in https://github.com/jacoco/jacoco/pull/529 and should be in 0.8.0.
Upvotes: 10
Reputation: 1330
As per official documentation, it's going to be released with 0.8.0
Filters for Code where Test Execution is Questionable or Impossible by Design
Private empty constructors that do not have arguments - Done
You can find details here.
Upvotes: 0
Reputation: 798
For this use case, reflection is perfectly acceptable, there are few and well known classes. The bellow code could be used with an automatic class detection based on the name. For sample ".*Factory" classes with additional asserts.
@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();
}
Upvotes: 1
Reputation: 216
There is no way to turn that option off. If you desperately need to meet some quality gate related to coverage you can always use a workaround and invoke these private constructors via reflection.
Upvotes: 1