question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

System Exit Extension: Test fails though it should pass

See original GitHub issue

Kotest 4.4.2

I encountered strange behaviour when using the System Exit Extension:

Minimum working example:

import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.StringSpec
import io.kotest.extensions.system.*
import io.kotest.matchers.shouldBe
import picocli.CommandLine
import picocli.CommandLine.Command
import java.util.concurrent.Callable
import kotlin.system.exitProcess

class SystemExitTest : StringSpec() {

    override fun listeners() = listOf(SpecSystemExitListener)

    init {
        "Test passes as expected" {
            shouldThrow<SystemExitException> {
                exitProcess(CommandLine(PicocliApp()).execute())
            }.exitCode shouldBe 42
        }

        "Test fails though it should pass" {
            shouldThrow<SystemExitException> {
                CommandLine(PicocliApp2()).execute()
            }.exitCode shouldBe 42
        }
    }
}

@Command
class PicocliApp : Callable<Int> {
    override fun call(): Int {
        return 42
    }
}

@Command
class PicocliApp2 : Callable<Int> {
    override fun call(): Int {
        exitProcess(42)
    }
}

I’m testing a command line application based on the https://picocli.info framework.

First test: PicocliApp app is called, returns an exit code, top level process exits with returned code. Everything is fine here.

Second test: PicocliApp app is called, app exits inside the overriden call function. Test fails though it should pass.

I tested the both same tests using Stefan Birkner’s System rules. Result: both tests pass (as expected).

I admit that it is a bit unusual to exit from the call function of a command. Certainly the better way of coding is following the convention to return an exit code and call System.exit from the main method with the return value of the execute method. Nonetheless, test 2 contains valid code which should be handled correctly from the test framework.

Thanks for investigating!

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:10 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
remkopcommented, Mar 9, 2021

An alternative would be to throw a Throwable from the security manager instead of Exception, because my guess is that libraries and applications are less likely to catch all Throwables (and cause the same issue with the test). However, “less likely” is not zero. 😃

The approach suggested by @sksamuel to store the last return code so it can be inspected is more robust.

Thanks all for raising this and the analysis! And nice work with the kotest library! 😃

0reactions
deiningcommented, Mar 8, 2021

What we can do is improve the listener to record every caught System.exit

Doesn’t that make sense?

I see it from a test user perspective: I called System.exit and want to test for this, but the test fails. Like said, other test systems perform different (=better) when confronted with my second test case.

You may also have a look at the perspective from the author of picocli.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Testing System.exit() with JUnit5 - Todd Ginsberg
Whenever the JVM does something interesting (like exiting, or reading a file), it first checks whether it has permission to do so.
Read more >
Dealing with System.exit(0) in JUnit tests - java - Stack Overflow
I am starting the application afresh in each test by putting each test method in a separate test case, and using the fork="yes"...
Read more >
SystemExit while debugging unit test method #3201 - GitHub
I have an "issue" in that debugging a test that completes successfully opens the Python extension's testlauncher.py with a SystemExit exception, ...
Read more >
run-tests.sh should exit with a failure code if any tests failed
Changing the exit code to always be 1 in case of any test failures and errors sounds fine to me. That said, the...
Read more >
Tag Archives: junit - Don't Panic!
exit() calls from application code can be tricky. This is because System.exit() terminates the JVM running it. If you're running JUnit, this is...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found