stefanbirkner/system-lambda

How to check SystemExit and SystemOut

tomaculum opened this issue · 4 comments

Hi all,

currently I am converting my tests from JUnit 4 to JUnit 5 but I have a bit of an issue with the following test:

    // JUnit 4

    @Rule
    public final SystemOutRule systemOutRule = new SystemOutRule().enableLog().mute();
    @Rule
    public final ExpectedSystemExit exit = ExpectedSystemExit.none();
    @Rule
    public ExpectedException exceptionRule = ExpectedException.none();

    @Test()
    public void testExample() {
        exit.expectSystemExit();
        exit.checkAssertionAfterwards(() -> {
            assertThat(systemOutRule.getLog(), is("OutputWithExit\n"));
            systemOutRule.clearLog();
        });
        Example.main();
        assertThat(systemOutRule.getLog(), is("OutputWithoutExit"));
        systemOutRule.clearLog();
    }

How do I achieve a similar result in JUnit 5 with the new system-lambda library?

Ignoring the SystemExit and just checking the SystemOut terminates some of my other running tests. And even running it independently does not work as expected.

This was my naive attempt to combine those two but even with fail() it results in a passed test.

    // JUnit 5

    @Test()
    public void testExample() throws Exception {
        int status = SystemLambda.catchSystemExit(() -> {
            String text  = tapSystemOut(() -> Example.main());
            fail();
        });
    }

I do not necessarily need to check those two cases in one test but it should not terminate my other tests. Hope this makes kind of sense.

TLDR; change the order and the test will work:

@Test
public void testExample() throws Exception {
  var text = tapSystemOut(() -> {
    catchSystemExit(Example::main);
  });
  assertThat(text, is("OutputWithExit\n"));
}

Your approach does not work because Example.main() calls System.exit(). Because of catchSystemExit an exception is thrown when System.exit() is called. This exception is rethrown by tapSystemOut (therefore fail() is not executed) and catched by catchSystemExit which extract the exit status and returns it.

IMO this is not a bug but it requires some documentation updates.

FYI The two lines after Example.main() are never executed. With System Rules all code that comes after the code that calls System.exit() is not executed.

It works, thank you very much!

Do you want to keep this issue open because of the documentation updates? From my side, this issue can be closed.

You can close it. I will create a new release that tackles the problem with better documentation and a helpful error message (if possible).