3

I have worked with junit test integration tests and controller tests in spring and usually we test the output of a method but when i tried to test a simple hello world in main method i had no idea how to go about it so will like to get any idea on what do write

public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }
}

This is the simple java class any idea how i can test it I tried to write something like this

public void mainMethodTest() throws Exception{

        System.out.println("hello world");
        String[] args = null;


        Assert.assertEquals(System.out.println("hello world"),App.main(args));
    }
valik
  • 2,014
  • 4
  • 24
  • 55
  • `System.out` prints to standard output - in order to capture that you'll need to start a new process (see `Runtime.exec`) and see what gets printed on the standard output. Do that, and you'll have tested if `System.out` works :) – giorgiga Feb 12 '18 at 21:47
  • https://stackoverflow.com/questions/1119385/junit-test-for-system-out-println – Sotirios Delimanolis Feb 12 '18 at 21:58

3 Answers3

6

You could assign to the System.out variable a ByteArrayOutputStream object which you store the reference in a variable.
Then invoke your main() method and assert that the String content of the ByteArrayOutputStream object contains the expected String:

@Test
public void main() throws Exception{                
    PrintStream originalOut = System.out; // to have a way to undo the binding with your `ByteArrayOutputStream` 
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    System.setOut(new PrintStream(bos));
    // action
    App.main(null);
    // assertion
    Assert.assertEquals("hello world", bos.toString());
    // undo the binding in System
    System.setOut(originalOut);
}

Why does it work ?

bos.toString() returns the "Hello World!" String passed in the method under test:

System.out.println( "Hello World!" );

as after setting System.out in this way : System.setOut(new PrintStream(bos));, the out variable refers to a PrintStream object that decorates the ByteArrayOutputStream object referenced by the bos variable. So any System.out invocations will write bytes in the ByteArrayOutputStream object.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • `setOut` requires a `PrintStream`, see my answer for details. – Lothar Feb 12 '18 at 21:54
  • @Lothar Indeed. Thanks :) Writing without compiler creates this kind of issue :) – davidxxx Feb 12 '18 at 21:56
  • i have only junit junit 4.8.1 test – valik Feb 12 '18 at 22:09
  • it doesnt allow for Annotation @Test – valik Feb 12 '18 at 22:09
  • If `assertEquals` fails your will introduce side effect in your test by leaving `System.out.println` pointing to custom stream. – tsolakp Feb 12 '18 at 22:12
  • The `@Test` annotation is included since JUnit 4. You use it. So it should work. Just add the import : `import org.junit.Test` – davidxxx Feb 12 '18 at 22:13
  • in the assert method i dont get how bos.string has a string hello world in it – valik Feb 12 '18 at 22:13
  • 1
    @tsolakp It is right. Doing it in a `finally` statement or a `@Before` method is preferable. – davidxxx Feb 12 '18 at 22:14
  • wow thats deep , where can i learn about such deep knowledge of java any reference books or something ? thats great thanks @davidxxx thanks – valik Feb 12 '18 at 22:30
  • @valik I edited to explain why it works. By reading it carefully and by testing yourself with a debugger in your IDE, you should get it I am sure – davidxxx Feb 12 '18 at 22:33
  • @valik Simple experience coming from working with a language. Sooner or later you come up with problems like these you spend time on solving. After a couple of years you end up with a stack of knowledge you collected over time. – Lothar Feb 13 '18 at 11:30
5

You can change your class this way

import java.io.PrintStream;

public class TestHelloWorld {
    
    public final static void main(String[] args) {
        doPrint(System.out);
    }
    
    static void doPrint(PrintStream ps) {
        ps.println("Hello World");
    }
}

and test the doPrint function by providing your own PrintStream you create around a ByteArrayOutputStream:

public void mainMethodTest() throws Exception{
    ByteArrayOutputStream data = new ByteArrayOutputStream();
    PrintStream ps = new PrintStream(data, true, "UTF-8");
    TestHelloWorld.doPrint(ps);
    ps.flush();
    Assert.assertEquals("Hello World" + System.getProperty("line.separator"), new String(data, "UTF-8"));
}

Another solution is to replace the system's PrintStream by your own:

System.setOut(new PrintStream(data, true, "UTF-8"));

but that's quite ugly and I try to avoid that. Above solution is more clear, easier to maintenance and you can be sure that no other part of a larger application is printing something to STDOUT while you do your test, leading to a failure of it.

Lee Meador
  • 12,829
  • 2
  • 36
  • 42
Lothar
  • 5,323
  • 1
  • 11
  • 27
1

You can run Junit from a main method if thats what you mean.

public static void main( String[] args )
{
    JUnitCore junit = new JUnitCore(); 
    Result result = null;
    try {        
         result = junit.run(MyTestClass.class);
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
    int passed = result.getRunCount()-result.getFailureCount();
}

public class MyTestClass{
    @Test
    public void testAllBrowsers(){
         //test code and asserts
    }
}
Mark D
  • 233
  • 3
  • 17