Java:如何测试调用 System.exit() 的方法? [英] Java: How to test methods that call System.exit()?

查看:38
本文介绍了Java:如何测试调用 System.exit() 的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些方法可以在某些输入上调用 System.exit().不幸的是,测试这些情况会导致 JUnit 终止!将方法调用放在新线程中似乎没有帮助,因为 System.exit() 会终止 JVM,而不仅仅是当前线程.是否有任何常见的模式来处理这个问题?例如,我可以用存根代替 System.exit() 吗?

有问题的类实际上是一个命令行工具,我试图在 JUnit 中测试它.也许 JUnit 根本不是适合这项工作的工具?欢迎对补充回归测试工具提出建议(最好是与 JUnit 和 EclEmma 集成良好的工具).

解决方案

确实,Derkeiler.com 建议:

  • 为什么 System.exit() ?
<块引用>

与其以 System.exit(whateverValue) 终止,为什么不抛出未经检查的异常?在正常使用中,它会一直漂移到 JVM 的最后一搏捕获器并关闭您的脚本(除非您决定在途中的某个地方捕获它,这在某一天可能会有用).

在 JUnit 场景中它会被 JUnit 框架捕获,它会报告某某测试失败,顺利进入下一个.

  • 防止System.exit()实际退出JVM:
<块引用>

尝试修改 TestCase 以与阻止调用 System.exit 的安全管理器一起运行,然后捕获 SecurityException.

公共类 NoExitTestCase 扩展了 TestCase{受保护的静态类 ExitException 扩展了 SecurityException{公共最终 int 状态;公共 ExitException(int status){super("逃不掉!");this.status = 状态;}}私有静态类 NoExitSecurityManager 扩展了 SecurityManager{@覆盖public void checkPermission(Permission perm){//允许任何事情.}@覆盖public void checkPermission(权限许可,对象上下文){//允许任何事情.}@覆盖public void checkExit(int status){super.checkExit(状态);抛出新的退出异常(状态);}}@覆盖protected void setUp() 抛出异常{super.setUp();System.setSecurityManager(new NoExitSecurityManager());}@覆盖protected void tearDown() 抛出异常{System.setSecurityManager(null);//或保存并恢复原始super.tearDown();}public void testNoExit() 抛出异常{System.out.println("印刷作品");}public void testExit() 抛出异常{尝试{System.exit(42);} catch (ExitException e){assertEquals("退出状态", 42, e.status);}}}

<小时>

2012 年 12 月更新:

Will 提议 在评论中 使用系统规则,一组 JUnit(4.9+) 规则,用于测试使用 java.lang.System 的代码.
这最初是由 Stefan Birkner他在 2011 年 12 月的回答.

System.exit(…)

<块引用>

使用 ExpectedSystemExit 规则来验证 System.exit(…) 被调用.
您也可以验证退出状态.

例如:

public void MyTest {@规则public final ExpectedSystemExit exit = ExpectedSystemExit.none();@测试公共无效 noSystemExit() {//通过}@测试公共无效 systemExitWithArbitraryStatusCode() {exit.expectSystemExit();System.exit(0);}@测试公共无效 systemExitWithSelectedStatusCode0() {exit.expectSystemExitWithStatus(0);System.exit(0);}}

I've got a few methods that should call System.exit() on certain inputs. Unfortunately, testing these cases causes JUnit to terminate! Putting the method calls in a new Thread doesn't seem to help, since System.exit() terminates the JVM, not just the current thread. Are there any common patterns for dealing with this? For example, can I subsitute a stub for System.exit()?

[EDIT] The class in question is actually a command-line tool which I'm attempting to test inside JUnit. Maybe JUnit is simply not the right tool for the job? Suggestions for complementary regression testing tools are welcome (preferably something that integrates well with JUnit and EclEmma).

解决方案

Indeed, Derkeiler.com suggests:

  • Why System.exit() ?

Instead of terminating with System.exit(whateverValue), why not throw an unchecked exception? In normal use it will drift all the way out to the JVM's last-ditch catcher and shut your script down (unless you decide to catch it somewhere along the way, which might be useful someday).

In the JUnit scenario it will be caught by the JUnit framework, which will report that such-and-such test failed and move smoothly along to the next.

  • Prevent System.exit() to actually exit the JVM:

Try modifying the TestCase to run with a security manager that prevents calling System.exit, then catch the SecurityException.

public class NoExitTestCase extends TestCase 
{

    protected static class ExitException extends SecurityException 
    {
        public final int status;
        public ExitException(int status) 
        {
            super("There is no escape!");
            this.status = status;
        }
    }

    private static class NoExitSecurityManager extends SecurityManager 
    {
        @Override
        public void checkPermission(Permission perm) 
        {
            // allow anything.
        }
        @Override
        public void checkPermission(Permission perm, Object context) 
        {
            // allow anything.
        }
        @Override
        public void checkExit(int status) 
        {
            super.checkExit(status);
            throw new ExitException(status);
        }
    }

    @Override
    protected void setUp() throws Exception 
    {
        super.setUp();
        System.setSecurityManager(new NoExitSecurityManager());
    }

    @Override
    protected void tearDown() throws Exception 
    {
        System.setSecurityManager(null); // or save and restore original
        super.tearDown();
    }

    public void testNoExit() throws Exception 
    {
        System.out.println("Printing works");
    }

    public void testExit() throws Exception 
    {
        try 
        {
            System.exit(42);
        } catch (ExitException e) 
        {
            assertEquals("Exit status", 42, e.status);
        }
    }
}


Update December 2012:

Will proposes in the comments using System Rules, a collection of JUnit(4.9+) rules for testing code which uses java.lang.System.
This was initially mentioned by Stefan Birkner in his answer in December 2011.

System.exit(…)

Use the ExpectedSystemExit rule to verify that System.exit(…) is called.
You could verify the exit status, too.

For instance:

public void MyTest {
    @Rule
    public final ExpectedSystemExit exit = ExpectedSystemExit.none();

    @Test
    public void noSystemExit() {
        //passes
    }

    @Test
    public void systemExitWithArbitraryStatusCode() {
        exit.expectSystemExit();
        System.exit(0);
    }

    @Test
    public void systemExitWithSelectedStatusCode0() {
        exit.expectSystemExitWithStatus(0);
        System.exit(0);
    }
}

这篇关于Java:如何测试调用 System.exit() 的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆