2

I have a functional test of Multi-threading system. The problem is that the system uses System.exit so my junit test doesn't catch this errors. So I want my test fail if somewhere System.exit was called, even in another threads.

I used Java: How to test methods that call System.exit()? to prevent JVM stop on System.exit and throw ExitException instead. Also I used http://blog.cedarsoft.com/2011/12/junit-rule-fail-tests-on-exceptionsfailed-assertions-in-other-threads/ to collect this exceptions. I want my test to stop after ExitException with fail. But this exception stops only current thread. I tried to call junitThread.interrupt() before throwing ExitException but it is works perfectly only for simple tests.

How can I break junit test on throwing ExitException in any thread if I can't modify thread creation code?

Community
  • 1
  • 1
nickotinus
  • 323
  • 5
  • 17

1 Answers1

1

Why does it call System.exit()? And why does it call System.exit() at a level you're covering with your unit test?

If you want to test the exiting code, your tests can spawn a process and check that it has exited as planned. If you want to test other functionality, better structure your application in such a way that the code under test doesn not have such nasty side effects.

In general though, I'd say that having individual threads call System.exit() is a strong indicator of bad architecture. If any thread can instantly kill the entire appication without giving other threads a chance to clean up you'll likely run into quite some problems quite soon.

And if your threads call some global shutdown handler (that you can override in your tests) instead of System.exit() you won't have a problem testing that functionality.

Update: When dealing with legacy code, my first step would be to isolate the System.exit() into a place where it can be replaced in tests. E.g. create a class like this:

// "Singleton" with replaceable instance
public class ShutdownHandler {
    private static ShutdownHandler instance = new ShutdownHandler();

    public static ShutdownHandler getInstance() {
        return instance;
    }

    public synchronized void shutdown() {
        // default implementation
        System.exit();
    }

    public static void setInstance(ShutdownHandler newInstance) {
        // (probably also check that this is only called in a test environment)
        instance = newInstance;
    }
}

Then replace all System.exit() calls with ShutdownHandler.getInstance().shutdown(). That won't change the application's functionality at all. But now you can replace the ShutdownHandler instance in your tests with an implementation that sets some flag + throws an exception instead of exiting -- and your tests can then check that flag to determine whether the app would have exited.

I can also recommend "Working Effectively With Legacy Code" by Robert C. Martin for more ideas on how to turn an old mess into something manageable.

creinig
  • 1,560
  • 12
  • 23