由于 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;
}
}
}