在JUnit测试中处理System.exit(0)

我正在为现有的Java Swing应用程序实现一些测试,这样我就可以安全地重构和扩展代码而不会破坏任何东西。 我开始在JUnit中进行一些unit testing,因为这似乎是最简单的入门方法,但现在我的首要任务是创建一些端到端的测试来整体运行应用程序。

我通过将每个测试方法放在一个单独的测试用例中,并在Ant的junit任务中使用fork="yes"选项,在每个测试中重新启动应用程序。 但是,我想要作为测试实现的一些用例涉及用户退出应用程序,这导致调用System.exit(0)的方法之一。 这被JUnit视为错误: junit.framework.AssertionFailedError: Forked Java VM exited abnormally

有没有办法告诉JUnit退出代码为零实际上是否正常?

我如何处理这个问题是安装一个在调用System.exit时抛出exception的安全管理器。 然后有代码捕获exception并且不会使测试失败。

 public class NoExitSecurityManager extends java.rmi.RMISecurityManager { private final SecurityManager parent; public NoExitSecurityManager(final SecurityManager manager) { parent = manager; } public void checkExit(int status) { throw new AttemptToExitException(status); } public void checkPermission(Permission perm) { } } 

然后在代码中,类似于:

 catch(final Throwable ex) { final Throwable cause; if(ex.getCause() == null) { cause = ex; } else { cause = ex.getCause(); } if(cause instanceof AttemptToExitException) { status = ((AttemptToExitException)cause).getStatus(); } else { throw cause; } } assertEquals("System.exit must be called with the value of " + expectedStatus, expectedStatus, status); 

库系统规则库有一个名为ExpectedSystemExit的JUnit规则。 使用此规则,您可以测试调用System.exit(…)的代码:

 public class MyTest { @Rule public final ExpectedSystemExit exit = ExpectedSystemExit.none(); @Test public void systemExitWithArbitraryStatusCode() { exit.expectSystemExit(); /* the code under test, which calls System.exit(...) * with an arbitrary status */ } @Test public void systemExitWithSelectedStatusCode0() { exit.expectSystemExitWithStatus(0); //the code under test, which calls System.exit(0) } } 

系统规则至少需要JUnit 4.9。

完全披露:我是系统规则的作者。

你能否将“系统退出”抽象成一个新的依赖项,这样在你的测试中你可能只有一个假记录了一个事实,即已经调用了exit(和值),但是使用了一个调用System.exit的实现。真正的应用?