442 votes

JUnit test pour System.out.println ()

J'ai besoin d'écrire des tests JUnit pour une ancienne application qui est mal conçue et écrit beaucoup de messages d'erreur sur la sortie standard. Lorsque la méthode getResponse (String request) se comporte correctement, elle renvoie une réponse 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);
}
 

Mais quand il est malformé en XML ou ne comprend pas la requête, il renvoie null et écrit des choses sur la sortie standard.

Existe-t-il un moyen d'affirmer la sortie de la console dans JUnit? Pour attraper des cas comme:

 System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());
 

692voto

dfa Points 54490

utiliser ByteArrayOutputStream et System.setXXX est simple:

 private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();

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

@After
public void cleanUpStreams() {
    System.setOut(null);
    System.setErr(null);
}
 

exemples de cas de test:

 @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());
}
 

J'ai utilisé ce code pour tester l'option de ligne de commande (affirmer que -version affiche la chaîne de version, etc etc)

108voto

Will Points 2403

Je sais que c'est un vieux fil, mais il y a une belle bibliothèque pour faire ceci:

Règles du système

Exemple tiré des docs:

 public void MyTest {
    @Rule
    public final StandardOutputStreamLog log = new StandardOutputStreamLog();

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

Il vous permettra également de piéger System.exit(-1) et d'autres choses qu'un outil de ligne de commande aurait besoin d'être testé.

40voto

user1909402 Points 61

Au lieu de rediriger System.out, je refactoriser la classe qui l'utilise System.out.println() par le passage d'un PrintStream comme collaborateur, et ensuite à l'aide d' System.out de la production et un Test d'Espion dans le test.

Dans La Production

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

Dans le Test

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

Discussion

De cette façon, la classe sous test devient testable par un simple, sans avoir besoin de indirect de la redirection de la sortie standard ou obscur interception avec un système de règle.

22voto

Brian Agnew Points 143181

Vous pouvez définir le flux d'impression System.out via setOut () (et pour in et err ). Pouvez-vous rediriger cela vers un flux d'impression qui enregistre dans une chaîne, puis inspecter cela? Cela semblerait être le mécanisme le plus simple.

(Je recommanderais, à un certain stade, de convertir l'application à un cadre de journalisation - mais je suppose que vous êtes déjà au courant de cela!)

9voto

mguymon Points 4527

@dfa réponse est grande, donc je l'ai pris un peu plus loin pour le rendre possible de faire le test des blocs de sortie.

J'ai d'abord créé TestHelper avec une méthode captureOutput qui accepte les annoymous classe CaptureTest. Le captureOutput méthode effectue le travail de définition et de démolir les flux de sortie. Lors de la mise en œuvre de l' CaptureOutputs' test méthode est appelée, elle a accès à la sortie de générer pour le bloc d'essai.

Source pour TestHelper:

public class TestHelper {

    public static void captureOutput( CaptureTest test ) throws Exception {
        ByteArrayOutputStream outContent = new ByteArrayOutputStream();
        ByteArrayOutputStream errContent = new ByteArrayOutputStream();

        System.setOut(new PrintStream(outContent));
        System.setErr(new PrintStream(errContent));

        test.test( outContent, errContent );

        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
        System.setErr(new PrintStream(new FileOutputStream(FileDescriptor.out)));

    }
}

abstract class CaptureTest {
    public abstract void test( ByteArrayOutputStream outContent, ByteArrayOutputStream errContent ) throws Exception;
}

Notez que TestHelper et CaptureTest sont définies dans le même fichier.

Ensuite, dans votre test, vous pouvez importer de la statique captureOutput. Voici un exemple d'utilisation de JUnit:

// imports for junit
import static package.to.TestHelper.*;

public class SimpleTest {

    @Test
    public void testOutput() throws Exception {

        captureOutput( new CaptureTest() {
            @Override
            public void test(ByteArrayOutputStream outContent, ByteArrayOutputStream errContent) throws Exception {

                // code that writes to System.out

                assertEquals( "the expected output\n", outContent.toString() );
            }
        });
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X