devlperMoose
devlperMoose

Reputation: 315

How to unit test java main method?

I have a class to which I must pass 2 arguments through its main method, if passed less than 2 args, it displays a system error message. I wrote a unit test for the main method here, when I run the test, it stops at "running" (shows neither pass nor fail). Please suggest.

Example.java

public class Example 
{
    private static String str1   = null;
    private static String str2   = null;

    public static void main(String[] args)
    {
        if( args.length != 2 )
        {
            call();
        }

        Example ex = new Example(args[0], args[1]);
        ex.getData();
    }

    public Example(String str1, String str2)
    {
        Example.str1 = str1;
        Example.str2 = str2;
    }

    public void getData(){
        System.out.println("Name is: "+str1);
        System.out.println("City is: "+str2);
    }

    private static void call()
    {
        System.err.println("Usage: String1 String2");
        System.err.println("Where: ");
        System.err.println("       String1 - Name");
        System.err.println("       String1 - City");
        System.exit(1);
    }   
}

ExampleTest.java

public class ExampleTest {
    @Test
    public void testPassingWrongNumberOfInputs() {
        StringBuffer sb = new StringBuffer();
        sb.append("Usage: String1 String2")
        .append("Where: ")
        .append("       String1 - Name")
        .append("       String1 - City");

        String expectedErrorMessage = sb.toString();

        ByteArrayOutputStream outContent = new ByteArrayOutputStream();
        System.setErr(new PrintStream(outContent));
        String[] args = {"one"};
        Example.main(args);

        assertEquals(expectedErrorMessage, outContent.toString());
    }
}

Upvotes: 5

Views: 25496

Answers (4)

GregT
GregT

Reputation: 1099

Rename the main method, and add a return value, so you can test it. Call this new method from main.

Upvotes: 0

devlperMoose
devlperMoose

Reputation: 315

I finally was able to write the unit test as shown in the following. I only tested if the method is hitting System.exit(1) code or not.

public class ExampleTest {
    private SecurityManager m;
    private TestSecurityManager sm;

    @Before
    public void setUp() 
    {
        m = System.getSecurityManager();
        sm = new TestSecurityManager ();
        System.setSecurityManager(sm);
    }

    @After
    public void tearDown()
    {   
        System.setSecurityManager(m);
    }

    @Test
    public void testPassingWrongNumberOfInputs() {
        try {
            Example.main(new String[] {"one"});
        } catch (SecurityException se) {
            assertEquals("1", se.getMessage());
        }
    }
}

class TestSecurityManager extends SecurityManager {
    @Override 
    public void checkPermission(Permission permission) {            
        if ("exitVM".equals(permission.getName())) 
        {
            throw new SecurityException("System.exit attempted and blocked.");
        }
    }
    @Override 
    public void checkExit(int status) {
        throw new SecurityException(Integer.toString(status));
    }
}

Upvotes: 2

Jose Martinez
Jose Martinez

Reputation: 11992

How about the following:

class TestingSecurityManager extends SecurityManager {
  @Override public void checkExit(int status) {
    throw new SecurityException();
  }
}

Then in your test...

public class ExampleTest {
    @Test
    public void testPassingWrongNumberOfInputs() {
        StringBuffer sb = new StringBuffer();
        sb.append("Usage: String1 String2")
        .append("Where: ")
        .append("       String1 - Name")
        .append("       String1 - City");

        String expectedErrorMessage = sb.toString();

        ByteArrayOutputStream outContent = new ByteArrayOutputStream();
        System.setErr(new PrintStream(outContent));
        String[] args = {"one"};

        TestSecurityManager sm = new TestSecurityManager ();
        System.setSecurityManager(sm);

        try {
            Example.main(args);
            //should throw
            fail("Should have thrown exception");
        } catch (SecurityException se) {
        }

        assertEquals(expectedErrorMessage, outContent.toString());
    }
}

Upvotes: 2

Kevin Hooke
Kevin Hooke

Reputation: 2621

Remove the System.exit(1) call, you don't need it. Your app will exit after main() completes anyway without an unneeded call to explicitly terminate the VM. This call is most likely causing your JUnit to stop executing before you get to your assertEquals statement, because you just told the VM to quit.

Upvotes: 0

Related Questions