2010-09-29 5 views
13

Estoy usando JUnit4 y Hibernate3 en mi proyecto. Hibernate depende de Slf4j y, por lo tanto, mi proyecto también incluye esta biblioteca. Ahora me gustaría utilizar Slf4j en pruebas unitarias para registrar información de prueba suplementaria. ¿Podría proporcionar un breve ejemplo de cómo debe verse mi prueba unitaria para registrar solo una línea de texto? Preferentemente sin duplicación de código en pruebas múltiples.¿Hay algún patrón simple de uso de slf4j en las pruebas unitarias?

Respuesta

10

también me gusta usar slf4j en mis pruebas JUnit para mi clase DAO. Ayuda cuando está creando una prueba nueva o modificando una anterior. Normalmente dejo mi antigua salida de registro al nivel de depuración y hago mis nuevas declaraciones de registro a nivel de información mientras sigo trabajando activamente en el código en ese método. Una de mis clases JUnit sería algo como esto:

package com.example.mydao; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
// other imports not shown... 

public class TestMyDAO extends TestCase { 

    private static final Logger logger = 
     LoggerFactory.getLogger(TestMyDAO.class); 


    public void testA() { 
     logger.debug("Logging from testA() method"); 
    } 

    public void testB() { 
     logger.debug("Logging from testB() method"); 
    } 

    public void testThatIAmWorkingOn() { 
     logger.info("Logging from my new test method at INFO level"); 
    } 

} 

estoy usando log4j como el proveedor de registro real, por lo que mi archivo de configuración log4j.xml se ve así:

<?xml version="1.0" encoding="UTF-8"?> 
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> 
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false"> 
    <appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender"> 
     <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%d %-5p [%c{1}] %m %n" /> 
     </layout> 
    </appender> 

    <logger name="com.example.mydao" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="org.hibernate" additivity="false"> 
     <level value="WARN" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="org.hibernate.connection.DriverManagerConnectionProvider" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="org.hibernate.connection.C3P0ConnectionProvider" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="com.mchange" additivity="false"> 
     <level value="WARN" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="com.mchange.v2.resourcepool.BasicResourcePool" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <logger name="com.mchange.v2.c3p0.C3P0Registry" additivity="false"> 
     <level value="INFO" /> 
     <appender-ref ref="consoleAppender"/> 
    </logger> 

    <root> 
     <priority value ="WARN" /> 
     <appender-ref ref="consoleAppender"/> 
    </root> 

</log4j:configuration> 

Esto me da la información nivel de salida de mi clase JUnit, así como algunas cosas útiles de Hibernate runtime y otras bibliotecas utilizadas con Hibernate. Ajústelo a su gusto.

Por último, tengo que asegurarse de que todas las siguientes bibliotecas son, en mi ruta de clase cuando yo haga las pruebas JUnit:

  • slf4j-api-1.6.0.jar
  • slf4j-log4j12-1.6.0.jar
  • log4j-1.2.16.jar
  • log4j.xml (configuración de mi archivo, que se muestra arriba)
  • Alguna versión del JUnit en tiempo de ejecución JAR
  • Todos los archivos JAR normalmente se encuentran cuando se ejecuta la aplicación en producción

Esto es lo que hago cuando uso log4j. Si usa una implementación de registro diferente, entonces ajuste en consecuencia. No importa si está usando una versión diferente de slf4j, siempre que la "API" y los JAR de implementación sean de la misma versión (los míos son ambos 1.6.0).

+0

Y para evitar la duplicación de código, podría mover las importaciones y la declaración 'Logger' a una subclase abstracta' TestCase'. –

11

¿Por qué quiere registrar cosas en su prueba de unidad? Las pruebas unitarias deben pasar o fallar y deben usar el marco de prueba para indicar eso. No desea leer los resultados para ver si la prueba pasó o falló. Y si está fallando, ejecutarlo en su IDE/depurador es la mejor manera de solucionarlo.

+11

Porque a veces es útil saber POR QUÉ una prueba falló, o quizás imprimir métricas de rendimiento en caso de que quiera mantenerlas a la vista. – BjornS

+6

Si desea realizar pruebas de rendimiento, hágalo de forma adecuada y capture y grafique los números. Ojeando casualmente algunos números de una carrera UT NO es la forma de medir el rendimiento. Y en cuanto a por qué falló una prueba, debe escribir sus afirmaciones para que el texto le diga qué salió mal. En el trabajo, nuestro producto tiene decenas de miles de pruebas unitarias; ¿Dónde crees que estaríamos si tuviéramos que leer los resultados de esos? – dty

+2

No dije las pruebas de rendimiento, simplemente le dije que lo mantuviera a raya como un ejemplo de por qué es posible que desee iniciar sesión en sus pruebas. En cuanto a su trabajo, sí, también tenemos decenas de miles de pruebas y se sorprenderá de la rapidez con que puede encontrar la información que desea relacionada con una prueba específica. Además, no necesitarás leerlos a menos que realmente lo necesites, y cuando realmente lo necesites, es muy útil que ya tengas los registros allí. – BjornS

-1

Parece ser un mal olor para mí.

Siempre debe evitar la inspección o verificación manual para comprobar la unidad.

unidad de prueba debe ser automatizado, la intervención humana sólo debería ser necesaria si sus herramientas de construcción que dicen que cierta prueba ha fallado, y la causa de fallo deberá proporcionarse utilizando todos los métodos de verificación (por ejemplo assertEquals)

+2

Claro que sí. El OP quería saber cómo se vería el código * debería * hacer esto, y muchos de nosotros estamos recomendando que ese código no exista. Así es como debería ser *. – iX3

+0

bastante interesante, otra respuesta de dyt es esencialmente decir algo similar (las personas deben evitar iniciar sesión en pruebas unitarias debido a blablabla). Mi respuesta es recibir más votos negativos. LOL –

+0

El registro durante las pruebas suele ser increíblemente valioso, especialmente cuando las pruebas fallan. Esto, por supuesto, debe equilibrarse con un exceso de registro cuando las pruebas están pasando o los registros no se pueden leer. – AntonPiatek

2

Utilizamos log4j como nuestro registrador de salida;

private static Logger log = LoggerFactory.getLogger(MyClassHere.class); 

slf4j debe encontrar y usar log4j sin problemas si lo configura correctamente. para hacer la vida más fácil, me gustaría utilizar este patrón de Eclipse, ya que se va a escribir el código un poco justo:

private static Logger log = LoggerFactory.getLogger(${enclosing_type}.class); 
${:import(org.slf4j.Logger,org.slf4j.LoggerFactory)} 

para las pruebas le recomiendo que no se elevan sobre el nivel del INFO y mantener la mayoría de las cosas a DEBUG . Si realmente quiere atrapar muchos errores de forma inteligente, le recomiendo examinar PositronLogger, que es un apéndice del archivo de registro que recogerá silenciosamente todo en TRACE, pero solo lo arrojará al archivo si captura ERROR; algo así como el tiempo de viaje :)

http://github.com/andreaja/PositronLogger

+0

Necesito hacer esto 'getLogger()' en cada prueba unitaria dentro de algún método '@ Before'-annotated, ¿verdad? – yegor256

+0

No, solo la referencia estática privada, entonces simplemente puede llamar a log.debug ("algunas cosas"); donde quieras Editar: debería aclarar; LoggerFactory.getLogger() es parte de la referencia estática, no necesita llamarlo en su @Before, simplemente ingréselo como campo en su clase de prueba y debería funcionar. Un breve ejemplo: class MyTests {private static Logger log = LoggerFactory.getLogger (MyTests.class); @Test public void magic() {log.info ("..."); }} – BjornS

0

Slf4j es una fachada de registro donde puede decidir la implementación en tiempo de ejecución. Slf4j es solo una API. Por ejemplo, puede usar log4j como la implementación subyacente. Para esto, debe incluir dos dependencias en su pom.xml.

<!-- Depend on slf4j API --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-api</artifactId> 
     <version>1.7.12</version> 
    </dependency> 
    <!-- Use log4j as the slf4j implementation --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-log4j12</artifactId> 
     <version>1.7.12</version> 
    </dependency> 

La cosa es, cuando se ejecuta pruebas de unidad en el IDE o a través de mvn test, puede ser molesto para configurar la configuración log4j. Especialmente de una manera que simplemente funciona sin tener que hacer nada. Log4j se niega a registrar nada de manera predeterminada, a menos que tenga un archivo log4j.properties en classpath o establezca -Dlog4j.configuration=file:///path/to/log4j.properties.

Una solución es poner en la prueba de la unidad, el código para configurar la configuración de log4j programación:

@BeforeClass 
    public static void beforeClass() { 
     BasicConfigurator.resetConfiguration(); 
     BasicConfigurator.configure(); 
    } 

Esto sólo funciona, sin embargo, tiene que ser puesto en cada prueba unidad que es un dolor. .

5

Otra solución es cambiar la implementación del registro a una implementación simple solo para pruebas.

Así que en su pom.xml

<!-- Depend on slf4j API --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-api</artifactId> 
     <version>1.7.12</version> 
    </dependency> 

    <!-- Use SimpleLogger as the slf4j implementation in test --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-simple</artifactId> 
     <version>1.7.12</version> 
     <scope>test</scope> 
    </dependency> 

    <!-- Use log4j as the slf4j implementation during runtime (not test) --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-log4j12</artifactId> 
     <version>1.7.12</version> 
     <scope>runtime</scope> 
    </dependency> 

El SimpleLogger simplemente registra todo en stderr por defecto y no requiere ningún archivo de configuración

+1

El nivel de registro predeterminado de SimpleLogger es INFO. Para cambiarlo a DEPURAR, por ejemplo, use la opción de JVM -Dorg.slf4j.simpleLogger.defaultLogLevel = DEPURAR –

0

Añadir registro cronológico al escribir nuevas pruebas es útil. Al mismo tiempo, cuando las pruebas se ejecutan en una canalización de CI o CD, desea que el registro se deshabilite (o al menos menos detallado). En ocasiones, las fallas son transitorias, especialmente en una ejecución de extremo a extremo, por lo que resulta útil contar con resultados relevantes en el registro de consola de trabajos de CI. Este artículo lo describe muy bien - https://gualtierotesta.wordpress.com/2015/11/01/tutorial-logging-during-tests/

Cuestiones relacionadas