在另一个线程中的某个地方使System.exit上的JUnit测试失败

时间:2013-05-28 08:28:37

标签: java multithreading junit

我对多线程系统进行了功能测试。问题是系统使用System.exit所以我的junit测试不会捕获这个错误。所以我希望我的测试失败,如果某个地方调用System.exit,即使在另一个线程中。

我使用Java: How to test methods that call System.exit()?来阻止JVM在System.exit上停止并抛出ExitException。我还使用http://blog.cedarsoft.com/2011/12/junit-rule-fail-tests-on-exceptionsfailed-assertions-in-other-threads/来收集此异常。 我希望我的测试在ExitException失败后停止。但是此异常仅停止当前线程。我尝试在抛出ExitException之前调用junitThread.interrupt(),但它仅对简单测试有效。

如果无法修改线程创建代码,如何在任何线程中抛出ExitException时断开junit测试?

1 个答案:

答案 0 :(得分:1)

为什么要拨打System.exit()?为什么它会在你用单元测试覆盖的级别上调用System.exit()

如果要测试现有代码,您的测试可以生成一个进程并检查它是否已按计划退出。如果你想测试其他功能,可以更好地构建应用程序,使被测代码不会产生如此严重的副作用。

总的来说,我会说让个别线程调用System.exit()是一个糟糕架构的强烈指标。如果任何线程可以在不给其他线程清理的情况下立即终止整个应用程序,那么很快就会遇到很多问题。

如果您的线程调用了一些全局关闭处理程序(您可以在测试中覆盖)而不是System.exit(),那么测试该功能就不会有问题。

更新:在处理遗留代码时,我的第一步是将System.exit()隔离到可以在测试中替换它的位置。例如。创建一个这样的类:

// "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;
    }
}

然后用System.exit()替换所有ShutdownHandler.getInstance().shutdown()次来电。这根本不会改变应用程序的功能。 但是现在你可以用一个实现来替换测试中的ShutdownHandler实例,该实现设置一些标志+抛出异常而不是退出 - 然后你的测试可以检查那个标志以确定是否应用程序将退出。

我还可以推荐罗伯特·C·马丁(Robert C. Martin)的“有效使用遗产代码”,以获得更多关于如何将旧的混乱变成可管理的东西的想法。