How to add test coverage to a private constructor?
This is the code:
package com.XXX;
public final class Foo {
private Foo() {
// intentionally empty
}
public static int bar() {
return 1;
}
}
This is the test:
package com.XXX;
public FooTest {
@Test
void testValidatesThatBarWorks() {
int result = Foo.bar();
assertEquals(1, result);
}
@Test(expected = java.lang.IllegalAccessException.class)
void testValidatesThatClassFooIsNotInstantiable() {
Class cls = Class.forName("com.XXX.Foo");
cls.newInstance(); // exception here
}
}
Works fine, the class is tested. But Cobertura says that there is zero code coverage of the private constructor of the class. How can we add test coverage to such a private constructor?
I don't entirely agree with Jon Skeet. I think that if you can get an easy win to give you coverage and eliminate the noise in your coverage report, then you should do it. Either tell your coverage tool to ignore the constructor, or put the idealism aside and write the following test and be done with it:
@Test
public void testConstructorIsPrivate() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Constructor<Foo> constructor = Foo.class.getDeclaredConstructor();
assertTrue(Modifier.isPrivate(constructor.getModifiers()));
constructor.setAccessible(true);
constructor.newInstance();
}
Well, there are ways you could potentially use reflection etc - but is it really worth it? This is a constructor which should never be called, right?
If there's an annotation or anything similar that you can add to the class to make Cobertura understand that it won't be called, do that: I don't think it's worth going through hoops to add coverage artificially.
EDIT: If there's no way of doing it, just live with the slightly reduced coverage. Remember that coverage is meant to be something which is useful to you - you should be in charge of the tool, not the other way round.
Although it's not necessarily for coverage, I created this method to verify that the utility class is well defined and do a bit of coverage as well.
/**
* Verifies that a utility class is well defined.
*
* @param clazz
* utility class to verify.
*/
public static void assertUtilityClassWellDefined(final Class<?> clazz)
throws NoSuchMethodException, InvocationTargetException,
InstantiationException, IllegalAccessException {
Assert.assertTrue("class must be final",
Modifier.isFinal(clazz.getModifiers()));
Assert.assertEquals("There must be only one constructor", 1,
clazz.getDeclaredConstructors().length);
final Constructor<?> constructor = clazz.getDeclaredConstructor();
if (constructor.isAccessible() ||
!Modifier.isPrivate(constructor.getModifiers())) {
Assert.fail("constructor is not private");
}
constructor.setAccessible(true);
constructor.newInstance();
constructor.setAccessible(false);
for (final Method method : clazz.getMethods()) {
if (!Modifier.isStatic(method.getModifiers())
&& method.getDeclaringClass().equals(clazz)) {
Assert.fail("there exists a non-static method:" + method);
}
}
}
I have placed the full code and examples in https://github.com/trajano/maven-jee6/tree/master/maven-jee6-test
I had made private the constructor of my class of static utility functions, to satisfy CheckStyle. But like the original poster, I had Cobertura complaining about the test. At first I tried this approach, but this doesn't affect the coverage report because the constructor is never actually executed. So really all this tests is if the constructor is remaining private - and this is made redundant by the accessibility check in the subsequent test.
@Test(expected=IllegalAccessException.class)
public void testConstructorPrivate() throws Exception {
MyUtilityClass.class.newInstance();
fail("Utility class constructor should be private");
}
I went with Javid Jamae's suggestion and used reflection, but added assertions to catch anybody messing with the class being tested (and named the test to indicate High Levels Of Evil).
@Test
public void evilConstructorInaccessibilityTest() throws Exception {
Constructor[] ctors = MyUtilityClass.class.getDeclaredConstructors();
assertEquals("Utility class should only have one constructor",
1, ctors.length);
Constructor ctor = ctors[0];
assertFalse("Utility class constructor should be inaccessible",
ctor.isAccessible());
ctor.setAccessible(true); // obviously we'd never do this in production
assertEquals("You'd expect the construct to return the expected type",
MyUtilityClass.class, ctor.newInstance().getClass());
}
This is so overkill, but I gotta admit I like the warm fuzzy feeling of 100% method coverage.
With Java 8, it is possible to find other solution.
I assume that you simply want to create utility class with few public static methods. If you can use Java 8, then you can use interface
instead.
package com.XXX;
public interface Foo {
public static int bar() {
return 1;
}
}
There is no constructor and no complain from Cobertura. Now you need to test only the lines you really care about.