7

I have written a method that is printing output to a console. How should I test it?

public class PrinterForConsole implements Printer<Item>{

   public void printResult(List<Item> items) {
        for (Item item: items){
            System.out.println("Name: " + item.getName());
            System.out.println("Number: " + item.getNumber());

            }
        }
}

currently, my test looks like this

public class TestPrinter{
    @Test
    public void printResultTest() throws Exception {
            (am figuring out what to put here)

        }
}

I have read the solution at this post (thanks @Codebender and @KDM for highlighting this) but don't quite understand it. How does the solution there test the print(List items) method? Hence, asking it afresh here.

Community
  • 1
  • 1
Roy
  • 277
  • 1
  • 5
  • 17
  • 1
    You might look into [JMockit](http://jmockit.org), which I think would allow you to mock `System.out.println`. However, I haven't tried specifically mocking this method. I've seen it used for other methods in `System`, but here you're using `out` which is a static field. There should be a way, though. – ajb Aug 27 '15 at 05:16
  • You don't really say *why* you don't understand the answer for the question this duplicates. – Raedwald Aug 27 '15 at 11:15
  • Ok, the reason why I don't understand the answer is because I was trying to test a method I created while the answers there seemed to test what the JVM already has test cases for. – Roy Aug 27 '15 at 13:24

5 Answers5

20

Since you have put you don't get what the duplicate question says, I will try to explain a little.

When you do, System.setOut(OutputStream), whatever the application writes to the console (using System.out.printX()) statements, instead get written to the outputStream you pass.

So, you can do something like,

public void printTest() throws Exception {
      ByteArrayOutputStream outContent = new ByteArrayOutputStream();
      System.setOut(new PrintStream(outContent));

      // After this all System.out.println() statements will come to outContent stream.

     // So, you can normally call,
     print(items); // I will assume items is already initialized properly.

     //Now you have to validate the output. Let's say items had 1 element.
     // With name as FirstElement and number as 1.
     String expectedOutput  = "Name: FirstElement\nNumber: 1" // Notice the \n for new line.

     // Do the actual assertion.
     assertEquals(expectedOutput, outContent.toString());
}
nwinkler
  • 52,665
  • 21
  • 154
  • 168
Codebender
  • 14,221
  • 7
  • 48
  • 85
5

The best way to test it is by refactoring it to accept a PrintStream as a parameter and you can pass another PrintStream constructed out of ByteArrayOutputStream and check what is printed into the baos.

Otherwise, you can use System.setOut to set your standard output to another stream. You can verify what is written into it after the method returns.

A simplified version with comments is below:

@Test
public void printTest() throws Exception {
    // Create our test list of items
    ArrayList<Item> items = new ArrayList<Item>();
    items.add(new Item("KDM", 1810));
    items.add(new Item("Roy", 2010));

    // Keep current System.out with us
    PrintStream oldOut = System.out;

    // Create a ByteArrayOutputStream so that we can get the output
    // from the call to print
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // Change System.out to point out to our stream
    System.setOut(new PrintStream(baos));

    print(items);

    // Reset the System.out
    System.setOut(oldOut);

    // Our baos has the content from the print statement
    String output = new String(baos.toByteArray());

    // Add some assertions out output
    assertTrue(output.contains("Name: KDM"));
    assertTrue(output.contains("Name: Roy"));

    System.out.println(output);
}

Note that if the print method throws an exception, the System.out is not reset. It is better to use setup and teardown methods to set and reset this.

Dakshinamurthy Karra
  • 5,353
  • 1
  • 17
  • 28
  • thanks, @KDM, could you provide a sample? – Roy Aug 27 '15 at 05:10
  • I flagged it as duplicate. Have a look at http://stackoverflow.com/questions/1119385/junit-test-for-system-out-println – Dakshinamurthy Karra Aug 27 '15 at 05:11
  • yup, i read this post before asking here, I don't quite get that post as I'm unable to relate it to how to test my method (please see last line in my post) – Roy Aug 27 '15 at 05:14
1

How about something like this.

@Test
    public void printTest() throws Exception {
        OutputStream os = new ByteArrayOutputStream();
        System.setOut(os);
        objectInTest.print(items);
        String actualOutput = os.toString("UTF-8");
        assertEquals(expectedOutput, actualOutput);
    }
Jose Martinez
  • 11,452
  • 7
  • 53
  • 68
  • thanks Jose, i see where you're going, how do I get the objectInTest from my printTest() method? – Roy Aug 27 '15 at 05:17
  • Your post did not have the name of the class being tested nor the constructor so I didnt include it. Without seeing the constructor and class name I don't know how to instantiate an instance of your class being tested. – Jose Martinez Aug 27 '15 at 05:35
0

This is the Simple Test Code :-

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

For more :JUnit test for System.out.println()

Community
  • 1
  • 1
Anand Dwivedi
  • 1,452
  • 13
  • 23
  • thanks, shldn't my test case be testing the 'print(List items)' method? – Roy Aug 27 '15 at 05:09
  • i'm actually testing a custom print method i wrote, not java's print method. Does that change how you would test printing to console? – Roy Aug 27 '15 at 05:24
  • If you believe the question is already answered somewhere else, flag it as duplicate instead of copy-pasting the ansewer (which doesn't even make sense in this case and lacks context) – kryger Aug 27 '15 at 09:46
0

Eventually, what I came up with is this (after going through all the answers and links to possible duplicates above).

import org.junit.Test;
@Test
public void shouldPrintToConsole() throws Exception {
        Item testItem = new Item("Name", "Number");
        List<Item> items = Arrays.asList(testItem);

        Printer print = new Printer();
        printer.printOutput(items);
    }

Read up on naming convention (shouldPrintToConsole()) for testing too. Wondering if this is the convention because I see many sites that follow and many that don't.

Roy
  • 277
  • 1
  • 5
  • 17