JUnit test for System.out.println()

前端 未结 13 1676
广开言路
广开言路 2020-11-22 03:18

I need to write JUnit tests for an old application that\'s poorly designed and is writing a lot of error messages to standard output. When the getResponse(String reque

相关标签:
13条回答
  • 2020-11-22 03:45

    Instead of redirecting System.out, I would refactor the class that uses System.out.println() by passing a PrintStream as a collaborator and then using System.out in production and a Test Spy in the test. That is, use Dependency Injection to eliminate the direct use of the standard output stream.

    In Production

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

    In the Test

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

    Discussion

    This way the class under test becomes testable by a simple refactoring, without having the need for indirect redirection of the standard output or obscure interception with a system rule.

    0 讨论(0)
  • 2020-11-22 03:49

    Full JUnit 5 example to test System.out (replace the when part):

    package learning;
    
    import static org.assertj.core.api.BDDAssertions.then;
    
    import java.io.ByteArrayOutputStream;
    import java.io.PrintStream;
    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    
    class SystemOutLT {
    
        private PrintStream originalSystemOut;
        private ByteArrayOutputStream systemOutContent;
    
        @BeforeEach
        void redirectSystemOutStream() {
    
            originalSystemOut = System.out;
    
            // given
            systemOutContent = new ByteArrayOutputStream();
            System.setOut(new PrintStream(systemOutContent));
        }
    
        @AfterEach
        void restoreSystemOutStream() {
            System.setOut(originalSystemOut);
        }
    
        @Test
        void shouldPrintToSystemOut() {
    
            // when
            System.out.println("example");
    
            then(systemOutContent.toString()).containsIgnoringCase("example");
        }
    }
    
    0 讨论(0)
  • 2020-11-22 03:53

    If the function is printing to System.out, you can capture that output by using the System.setOut method to change System.out to go to a PrintStream provided by you. If you create a PrintStream connected to a ByteArrayOutputStream, then you can capture the output as a String.

    // Create a stream to hold the output
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    PrintStream ps = new PrintStream(baos);
    // IMPORTANT: Save the old System.out!
    PrintStream old = System.out;
    // Tell Java to use your special stream
    System.setOut(ps);
    // Print some output: goes to your special stream
    System.out.println("Foofoofoo!");
    // Put things back
    System.out.flush();
    System.setOut(old);
    // Show what happened
    System.out.println("Here: " + baos.toString());
    
    0 讨论(0)
  • 2020-11-22 03:54

    If you were using Spring Boot (you mentioned that you're working with an old application, so you probably aren't but it might be of use to others), then you could use org.springframework.boot.test.rule.OutputCapture in the following manner:

    @Rule
    public OutputCapture outputCapture = new OutputCapture();
    
    @Test
    public void out() {
        System.out.print("hello");
        assertEquals(outputCapture.toString(), "hello");
    }
    
    0 讨论(0)
  • 2020-11-22 03:55

    for out

    @Test
    void it_prints_out() {
    
        PrintStream save_out=System.out;final ByteArrayOutputStream out = new ByteArrayOutputStream();System.setOut(new PrintStream(out));
    
        System.out.println("Hello World!");
        assertEquals("Hello World!\r\n", out.toString());
    
        System.setOut(save_out);
    }
    

    for err

    @Test
    void it_prints_err() {
    
        PrintStream save_err=System.err;final ByteArrayOutputStream err= new ByteArrayOutputStream();System.setErr(new PrintStream(err));
    
        System.err.println("Hello World!");
        assertEquals("Hello World!\r\n", err.toString());
    
        System.setErr(save_err);
    }
    
    0 讨论(0)
  • 2020-11-22 03:56

    @dfa answer is great, so I took it a step farther to make it possible to test blocks of ouput.

    First I created TestHelper with a method captureOutput that accepts the annoymous class CaptureTest. The captureOutput method does the work of setting and tearing down the output streams. When the implementation of CaptureOutput's test method is called, it has access to the output generate for the test block.

    Source for 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;
    }
    

    Note that TestHelper and CaptureTest are defined in the same file.

    Then in your test, you can import the static captureOutput. Here is an example using 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() );
                }
            });
    }
    
    0 讨论(0)
提交回复
热议问题