java - unitaria - JUnit: prueba de clase auxiliar con solo métodos estáticos
sintaxis junit (4)
Estoy probando una clase de ayuda con solo métodos estáticos con JUnit4 y Cobertura. Métodos de prueba fue tarea fácil y ya está hecho.
Sin embargo, la cobertura muestra que la clase no está completamente cubierta por las pruebas, ya que no está instanciada en ninguna parte.
No quiero crear una instancia de esta clase (es una clase de ayuda), por lo que la primera solución es ocultar el constructor (que generalmente es un buen enfoque para la clase de ayuda).
Entonces la cobertura se queja de que el constructor privado vacío no está cubierto por pruebas.
¿Hay alguna solución para lograr una cobertura de código del 100% para tal situación?
Se requiere la cobertura del código de la gerencia de nivel superior (en este caso), por lo que para mí obtener el 100% para esta clase en particular es muy útil.
Hay varias soluciones:
Puedes agregar un constructor público y llamarlo desde una prueba. Si bien no tiene sentido, tampoco duele (mucho).
Cree una instancia estática ficticia (puede llamar al constructor privado aquí). Feo, pero puedes darle un nombre al campo para comunicar tu intención (
JUST_TO_SILENCE_COBERTURA
es un buen nombre).Puedes dejar que tu prueba extienda la clase de ayuda. Eso llamará intrínsecamente al constructor predeterminado, pero su clase auxiliar ya no puede ser
final
.
Sugiero el último enfoque, especialmente porque la clase ya no puede ser final
. Si un consumidor de su código desea agregar otro método auxiliar, ahora puede extender la clase existente y recibir un identificador para acceder a todos los métodos auxiliares. Esto crea un acoplamiento de los métodos de ayuda que comunican la intención (estos pertenecen juntos), lo cual es imposible si la clase de ayuda es final
Si desea evitar que los usuarios ejemplifiquen accidentalmente la clase de ayuda, hágalo abstract
lugar de usar un constructor oculto.
No.
A menos que llame explícitamente al constructor privado (que sería un código incorrecto) no podrá cubrir esas líneas.
Obtener una cobertura del 100% en todos los casos es bueno, pero hay algunos casos en los que esto no es posible. Por supuesto, si tiene una clase que nunca se crea una instancia, Cobertura obtendrá esto como una cobertura de prueba no completa, porque esas líneas de código están realmente en la clase, pero no están probadas.
El hecho es que nunca llamarás a un constructor privado (supongo que has ocultado al constructor haciéndolo privado), así que no me molestaría. La prueba debe consistir en obtener lo que espera, y aunque estoy de acuerdo en que una cobertura del 100% es buena, en algunos casos (como este) esto no es útil.
Eche un vistazo al 100% de la cobertura del código también.
Si es absolutamente necesario lograr una cobertura del 100% del código (los méritos de eso se pueden debatir en cualquier otro lado), se puede lograr utilizando la reflexión en sus pruebas. Como costumbre, cuando implemento una clase de utilidad solo estática, agrego un constructor privado para asegurar que no se puedan crear instancias de la clase. Por ejemplo:
/**
* Constructs a new MyUtilities.
* @throws InstantiationException
*/
private MyUtilities() throws InstantiationException
{
throw new InstantiationException("Instances of this type are forbidden.");
}
Entonces tu prueba podría verse algo como esto:
@Test
public void Test_Constructor_Throws_Exception() throws IllegalAccessException, InstantiationException {
final Class<?> cls = MyUtilties.class;
final Constructor<?> c = cls.getDeclaredConstructors()[0];
c.setAccessible(true);
Throwable targetException = null;
try {
c.newInstance((Object[])null);
} catch (InvocationTargetException ite) {
targetException = ite.getTargetException();
}
assertNotNull(targetException);
assertEquals(targetException.getClass(), InstantiationException.class);
}
Básicamente, lo que está haciendo aquí es obtener la clase por nombre, encontrar los constructores en ese tipo de clase, establecerla en público (la llamada setAccessible
), llamar al constructor sin argumentos y luego asegurarse de que la excepción de destino que se produce es una InstantiationException
.
De todos modos, como dijiste, el requisito de cobertura de código del 100% aquí es un poco molesto, pero parece que está fuera de tus manos, así que hay poco que puedas hacer al respecto. De hecho, he usado enfoques similares a los anteriores en mi propio código, y lo encontré beneficioso, pero no desde una perspectiva de prueba. Más bien, simplemente me ayudó a aprender un poco más sobre la reflexión de lo que sabía antes :)