2009-06-03 9 views
6

He encontrado una solución, vea mi propia respuesta a continuación. ¿Alguien tiene uno más elegante?¿Puedo ejecutar las pruebas JUnit automáticamente una vez con todos los registros activados y una vez con todos los registros deshabilitados?

Quiero hacer esto para aumentar la cobertura del código y encontrar errores sutiles.

asumir la siguiente clase a ensayar:

public class Foo { 
    private final Logger logger = LoggerFactory.getLogger(Foo.class); 
    public void bar() { 
     String param=[..]; 
     if(logger.isInfoEnabled()) logger.info("A message with parameter {}", param); 

     if(logger.isDebugEnabled()) { 
      // some complicated preparation for the debug message 
      logger.debug([the debug message]); 
     } 
    } 
} 

y la siguiente prueba de clase:

public class FooTest { 
    @Test 
    public void bar() { 
     Foo foo=new Foo(); 
     foo.bar(); 
    } 
} 

Una herramienta de código-cobertura como, por ejemplo, Cobertura informará correctamente que solo se han verificado algunas de las ramas condicionales.

la información y la depuración se activan o desactivan para el registrador.

Además de verse mal en su puntaje de cobertura, esto representa un riesgo real.

¿Qué pasa si hay algún efecto secundario causado por el código dentro if (logger.isDebugEnabled())? ¿Qué pasa si su código solo funciona si DEPURACIÓN está habilitada y falla miserablemente si el nivel de registro está establecido en INFO? (En realidad, esto sucedió en uno de nuestros proyectos: p)

Así que mi conclusión es que el código contiene declaraciones registrador debe siempre ser probados una vez con todo el registro habilitado y una vez con todo el registro desactivado ...

Es Hay una manera de hacer algo así con JUnit? Sé cómo habilitar o deshabilitar globalmente todos mis registros en Logback, por lo que el problema es: ¿cómo puedo ejecutar las pruebas dos veces, una con el registro habilitado, una vez con el registro deshabilitado?

p.s. Estoy al tanto de this question pero no creo que sea un duplicado. Me preocupan menos los valores de cobertura absolutos, pero sobre errores sutiles y difíciles de encontrar que podrían estar contenidos dentro de un if (logger.isDebugEnabled()).

Respuesta

4

He resuelto este problema implementando una clase base que las clases de prueba deberían extenderse si se desea dicha funcionalidad.

El artículo Writing a parameterized JUnit test contenía la solución.

Consulte LoggingTestBase para la clase base de registro y LoggingTestBaseExampleTest para obtener un ejemplo sencillo que lo esté usando.

Cada método de ensayo contenida se ejecuta tres veces:

1. Se ejecuta utilizando el registro como se define en logback-test.xml como de costumbre. Se supone que esto ayuda mientras escribe/depura las pruebas.

2. Se ejecuta con todos los registros habilitados y escritos en un archivo. Este archivo se elimina después de la prueba.

3. Se ejecuta con todos los registros deshabilitados.

Sí, LoggingTestBase necesita documentación;)

+0

Nota: no se considera una buena práctica administrar niveles de registro para una aplicación típica escribiendo la configuración desde la aplicación. Los marcos de registro están diseñados para gestionar esto externo a la aplicación. –

+0

Son pruebas unitarias, no es una aplicación. Además, ciertamente hay casos en los que cambiar la configuración de nivel de loog tiene sentido, p. una opción de línea de comandos '-v' de una aplicación de consola. – Huxi

+0

Puede configurar el logback programáticamente sin Joran. Tendrás código más corto. Además, si la configuración se realizó programáticamente, puede restaurar la configuración anterior al final de cada prueba. Holler en logback-dev si desea ver el código de muestra. De lo contrario, muy buen trabajo! – Ceki

2

Recomendaría cambiar de JUnit a TestNG. TestNG tiene muchas funciones avanzadas sobre JUnit. Le permite ejecutar sus pruebas varias veces con una configuración diferente y creo que eso es lo que necesita

+0

¿Se pueden combinar JUnit y TestNG? Estoy hablando más o menos de la integración de Maven 2 aquí ... todas nuestras pruebas son pruebas JUnit ... – Huxi

+0

Sí, TestNG puede ejecutar pruebas JUnit. Lo uso en proyectos maven2 todo el tiempo – artemb

+0

Convertir una prueba de TestNG a JUnit es fácil, aunque consume mucho tiempo – artemb

3

has necesitado simple mantenimiento de dos archivos de configuración de registro separado? Cada uno se registraría en diferentes niveles desde el registrador de raíz.

Todo el registro desactivado:

... 
<root> 
    <priority value="OFF"/> 
    <appender-ref ref="LOCAL_CONSOLE"/> 
</root> 
... 

Todo el registro activado:

... 
<root> 
    <priority value="ALL"/> 
    <appender-ref ref="LOCAL_CONSOLE"/> 
</root> 
... 

ejecución sería especificar diferentes configuraciones en la ruta de clase a través de un parámetro del sistema:

-Dlog4j.configuration=path/to/logging-off.xml 
-Dlog4j.configuration=path/to/logging-on.xml 
+0

Estaba pensando más en las líneas de Maven 2 y Logback. Tener dos configuraciones e inicializar el marco de trabajo no es el problema. Ejecutar las pruebas dos veces llamando al método de configuración del registrador respectivo de antemano es mi problema. Debería haberlo expresado más claramente, creo. – Huxi

+1

puede especificar los parámetros del sistema en maven en un perfil elegible. Desea dos perfiles, uno con registro y otro sin él. Conseguir que ambos ejecuten con un comando está más allá de mi alcance – Jherico

+0

@Huxi: tenga en cuenta que el archivo de configuración de registro no solo sirve para inicializar el marco de registro, sino también para controlar los niveles de registro (que es lo que intenta hacer). Al realizar dos (o tres) pruebas, está logrando lo que desea sin obligar a los desarrolladores a crear 3 pruebas de unidad para esta funcionalidad (que es lo que está proponiendo). Puede controlar qué configuración de registro elige cada ejecución utilizando diferentes perfiles de maven. Un script puede encargarse de ejecutar las ejecuciones en un comando. –

1

eqbridges sugerencia de simplemente ejecutar las pruebas dos veces con diferentes contextos de registro parece el más simple. No tiene que recordar codificar la lógica en cada prueba bendecida, para obtener una gran ventaja. La otra es que se puede ver qué nivel de registro es el culpable con mucha facilidad.

Dicho esto, hay un par de estrategias si solo tiene que hacer esto en una prueba.

Para 3.8 Pondría todo en suites y haré dos suites, una para cada nivel de registro, que establece el nivel de registro antes de ejecutar las pruebas. Esto es funcionalmente lo mismo que ejecutar todo el conjunto de pruebas dos veces con diferentes parámetros de línea de comandos, excepto que lo obtiene con una ejecución.

En JUnit 4.x un par de opciones adicionales vienen a la mente:

Uno de ellos es un corredor personalizado. Aunque no puedo pensar en todo lo que tendrías que hacer para que esto funcione, pero un corredor que realmente ejecuta la prueba dos veces y anota la prueba con @RunWith tu corredor personalizado podría funcionar.

El otro es pruebas parametrizadas. Aunque en realidad tendría que configurar cada prueba para tomar parámetros (esto requiere un constructor que tome los argumentos) y luego establecer el nivel de registro de acuerdo con el parámetro.

EDITAR: En respuesta a su solicitud de instrucciones sobre las pruebas paramterizadas, here es el javadoc en el corredor para comenzar, y here es una guía más práctica.

+0

¿Tiene algún enlace para docu sobre pruebas parametrizadas? Las preguntas más frecuentes de JUnit se actualizaron por última vez en 2006 y no pude encontrar nada parecido ... ¿Qué está pasando en junit.org? El libro de cocina parece estar desactualizado, también ... – Huxi

+0

Gracias por la sugerencia de "pruebas parametrizadas". Encontré algo de documentación, veo mi solución. – Huxi

0

Si cree que tiene demasiados registros si enciende todo, tal vez podría intentar reducir la cantidad de registros. No es muy útil si es demasiado para que la computadora procuda, no importa que un humano lea.

+0

Enrutar todo el registro en un archivo temporal para que la salida no esté saturada de mensajes de registro inútiles. El objetivo de mi pregunta es que me gustaría poder probar ambos escenarios: todos los registros activados y todos los registros desactivados. Realmente teníamos la situación de que una clase funcionaría si se ejecuta con depuración habilitada y no con la información habilitada. Me gustaría detectar estos problemas de manera general. – Huxi

Cuestiones relacionadas