Prueba JUnit para System.out.println()

Resuelto Mike Minicki asked hace 15 años • 15 respuestas

Necesito escribir pruebas JUnit para una aplicación antigua que está mal diseñada y escribe muchos mensajes de error en la salida estándar. Cuando el getResponse(String request)método se comporta correctamente, devuelve una respuesta XML:

@BeforeClass
public static void setUpClass() throws Exception {
    Properties queries = loadPropertiesFile("requests.properties");
    Properties responses = loadPropertiesFile("responses.properties");
    instance = new ResponseGenerator(queries, responses);
}

@Test
public void testGetResponse() {
    String request = "<some>request</some>";
    String expResult = "<some>response</some>";
    String result = instance.getResponse(request);
    assertEquals(expResult, result);
}

Pero cuando obtiene un formato XML incorrecto o no comprende la solicitud, regresa nully escribe algunas cosas en la salida estándar.

¿Hay alguna forma de hacer valer la salida de la consola en JUnit? Para detectar casos como:

System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());
Mike Minicki avatar Jul 13 '09 20:07 Mike Minicki
Aceptado

usar ByteArrayOutputStream y System.setXXX es simple:

private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
private final PrintStream originalOut = System.out;
private final PrintStream originalErr = System.err;

@Before
public void setUpStreams() {
    System.setOut(new PrintStream(outContent));
    System.setErr(new PrintStream(errContent));
}

@After
public void restoreStreams() {
    System.setOut(originalOut);
    System.setErr(originalErr);
}

casos de prueba de muestra:

@Test
public void out() {
    System.out.print("hello");
    assertEquals("hello", outContent.toString());
}

@Test
public void err() {
    System.err.print("hello again");
    assertEquals("hello again", errContent.toString());
}

Utilicé este código para probar la opción de línea de comando (afirmando que -version genera la cadena de versión, etc., etc.)

Editar: versiones anteriores de esta respuesta llamadas System.setOut(null)después de las pruebas; Esta es la causa de las NullPointerExceptions a las que se refieren los comentaristas.

dfa avatar Jul 13 '2009 13:07 dfa

Sé que este es un hilo antiguo, pero hay una buena biblioteca para hacer esto: Ejemplo de reglas del sistema
de los documentos:

public void MyTest {
    @Rule
    public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();

    @Test
    public void overrideProperty() {
        System.out.print("hello world");
        assertEquals("hello world", systemOutRule.getLog());
    }
}

También le permitirá capturar System.exit(-1)y otras cosas para las que sería necesario probar una herramienta de línea de comandos.

Will avatar Mar 02 '2013 13:03 Will

En lugar de redirigir System.out, refactorizaría la clase que usa System.out.println()pasando a PrintStreamcomo colaborador y luego usándola System.outen producción y Test Spy en la prueba. Es decir, utilice la inyección de dependencia para eliminar el uso directo del flujo de salida estándar.

En producción

ConsoleWriter writer = new ConsoleWriter(System.out));

En la prueba

ByteArrayOutputStream outSpy = new ByteArrayOutputStream();
ConsoleWriter writer = new ConsoleWriter(new PrintStream(outSpy));
writer.printSomething();
assertThat(outSpy.toString(), is("expected output"));

Discusión

De esta manera, la clase bajo prueba se vuelve comprobable mediante una simple refactorización, sin necesidad de una redirección indirecta de la salida estándar o una intercepción oscura con una regla del sistema.

user1909402 avatar Jan 19 '2014 11:01 user1909402

Puede configurar el flujo de impresión System.out a través de setOut() (y para iny err). ¿Puedes redirigir esto a una secuencia de impresión que graba en una cadena y luego inspeccionarla? Éste parecería ser el mecanismo más sencillo.

(Yo recomendaría, en algún momento, convertir la aplicación a algún marco de registro, ¡pero sospecho que ya lo sabe!)

Brian Agnew avatar Jul 13 '2009 13:07 Brian Agnew

Ligeramente fuera de tema, pero en caso de que algunas personas (como yo, cuando encontré este hilo por primera vez) puedan estar interesadas en capturar la salida del registro a través de SLF4J, el JUnit de commons-testing@Rule podría ayudar:

public class FooTest {
    @Rule
    public final ExpectedLogs logs = new ExpectedLogs() {{
        captureFor(Foo.class, LogLevel.WARN);
    }};

    @Test
    public void barShouldLogWarning() {
        assertThat(logs.isEmpty(), is(true)); // Nothing captured yet.

        // Logic using the class you are capturing logs for:
        Foo foo = new Foo();
        assertThat(foo.bar(), is(not(nullValue())));

        // Assert content of the captured logs:
        assertThat(logs.isEmpty(), is(false));
        assertThat(logs.contains("Your warning message here"), is(true));
    }
}

Descargo de responsabilidad :

  • Desarrollé esta biblioteca porque no pude encontrar ninguna solución adecuada para mis propias necesidades.
  • Por el momento sólo están disponibles enlaces para log4j, log4j2y logback, pero estaré feliz de agregar más.
Marc Carré avatar Dec 11 '2014 08:12 Marc Carré