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

Ben*_*Ben 11 java junit

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

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

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

Ste*_*ner 27

系统规则库有一个名为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)
    }
}
Run Code Online (Sandbox Code Playgroud)

系统规则至少需要JUnit 4.9.

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


Tof*_*eer 8

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

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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在代码中,类似于:

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);
Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 6

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