2012-03-14 12 views
27

Estoy probando una clase auxiliar con solo métodos estáticos con JUnit4 y Cobertura. Los métodos de prueba fueron una tarea fácil y ya están hechos.JUnit: prueba la clase auxiliar con solo métodos estáticos

Sin embargo, cobertura muestra que la clase no está cubierta por pruebas por completo, ya que no se instancia en ninguna parte.

No quiero crear una instancia de esta clase (es una clase auxiliar), así que la primera solución es ocultar el constructor (que generalmente es un buen enfoque para la clase auxiliar).

Then cobertura se queja de que el constructor privado vacío no está cubierto por las pruebas.

¿Hay alguna solución para lograr una cobertura de código del 100% para esa situación?

La cobertura de código es necesaria para la gestión de nivel superior (en este caso), por lo que para mí obtener 100% para esta clase en particular es bastante útil.

Respuesta

27

hay varias soluciones:

  1. Se puede añadir un constructor público y lo llaman de una prueba. Si bien no tiene sentido, tampoco duele (mucho).

  2. Crea una instancia ficticia estática (aquí puedes llamar al constructor privado). Feo, pero puede darle un nombre al campo para comunicar su intención (JUST_TO_SILENCE_COBERTURA es un buen nombre).

  3. Puedes dejar que tu prueba extienda la clase de ayuda. Eso intrínsecamente llamará al constructor predeterminado pero su clase auxiliar ya no puede ser final.

Sugiero la última aproximación, especialmente porque la clase ya no puede ser final. Si un consumidor de su código desea agregar otro método auxiliar, ahora puede ampliar 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 comunica la intención (estos corresponden juntos) - lo cual es imposible si la clase de ayuda es final

Si desea impedir que los usuarios crear una instancia de forma accidental la clase de ayuda, que sea abstract en lugar de utilizar un constructor oculto.

+1

El tercer enfoque es, en mi opinión, el mejor también, porque no influye en absoluto en el código (solo pruebas). Yo tomaría esto. Gracias por ayudar. –

2

menos que llame al constructor privado de forma explícita (lo que sería malo código) usted no será capaz de cubrir esas líneas.

7

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 se prueban.

El hecho es que nunca llamarás a un constructor privado (supongo que has ocultado el 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 la cobertura del 100% es buena, en algunos casos (como esta) esto no es útil.

Echa un vistazo a 100% Code Coverage también.

+2

A veces se requiere la cobertura de código de la gerencia de nivel superior (en este caso lo es), así que para mí obtener 100% para esta clase en particular es bastante útil. Y sí, soy consciente de la ridiculez de este enfoque. Sin embargo, gracias por el enlace del artículo. –

27

Si necesita absolutamente obtener una cobertura de código del 100% - los méritos de eso se pueden debatir en otra parte :) - puede lograrlo mediante la reflexión en sus pruebas. Como hábito, 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."); 
} 

A continuación, la prueba podría ser 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 estamos haciendo aquí es conseguir la clase por su nombre, la búsqueda de los constructores en ese tipo de clase, el establecimiento a público (la llamada setAccessible), invocando al constructor sin argumentos, y luego asegurando que la excepción de destino lanzada sea InstantiationException.

De todos modos, como dijiste, el requisito de cobertura del código del 100% aquí es un poco molesto, pero parece que no está en tus manos, por lo que hay poco que puedes hacer al respecto. De hecho, he usado enfoques similares a los anteriores en mi propio código, y me pareció beneficioso, pero no desde una perspectiva de prueba. Más bien, me ayudó a aprender un poco más acerca de la reflexión de lo que sabía antes :)

+1

+1 Buen truco :-) –

+0

+1, ¡solución inteligente! – JW8

+0

¿Por qué hay un 'retorno' presente en el bloque catch? La prueba siempre regresará verdadera. ;) –

Cuestiones relacionadas