Can';t mock java.lang.System#exit(int)方法与PowerMock

Can';t mock java.lang.System#exit(int)方法与PowerMock,java,testng,powermock,powermockito,Java,Testng,Powermock,Powermockito,我的应用程序有一个流,在它的最后调用方法System.exit(int) 我试图通过使用TestNG运行测试来测试这个流 然而,在运行测试时,我收到了一条奇怪的消息,尽管测试已经完成: 为了找到根本原因,我从实际流中删除了System.exit(int),测试按预期通过,因此这里的问题是System.exit(int)方法 为了解决这个问题,我试图模仿这个有问题的方法,但找不到正确的方法。这就是我所做的 我在tests类的@PrepareForTest下添加了java.lang.System.

我的应用程序有一个流,在它的最后调用方法
System.exit(int)

我试图通过使用TestNG运行测试来测试这个流

然而,在运行测试时,我收到了一条奇怪的消息,尽管测试已经完成:

为了找到根本原因,我从实际流中删除了
System.exit(int)
,测试按预期通过,因此这里的问题是
System.exit(int)
方法

为了解决这个问题,我试图模仿这个有问题的方法,但找不到正确的方法。这就是我所做的

  • 我在tests类的
    @PrepareForTest
    下添加了
    java.lang.System.class
  • 在测试中添加了
    PowerMockito.mockStatic(java.lang.System.class)
  • 我试着用两种方式模拟该方法:

    a

    以这种方式运行时,模拟似乎不起作用,因为我在测试结束时收到的消息与在System.exit(int)上不应用任何模拟时得到的消息相同

  • b

    通过这种方式,我在测试开始时得到了以下异常:

    org.powermock.reflect.exceptions.MethodNotFoundException: No method found with name 'exit' with parameter types: [ <none> ] in class java.lang.System.
    
    org.powermock.reflect.exceptions.MethodNotFoundException:在类java.lang.System中找不到名为“exit”且参数类型为[]的方法。
    
    我已经以这种方式模拟了一些方法,不知道为什么使用
    System.exit(int)
    它不起作用

    有什么想法吗?
    谢谢

    有趣的问题,我也不知道,但显然,这是不需要使用Powermock,通过使用SecurityManager就可以实现的。引述:

    今天我在为我们的一个命令行工具编写测试,我 这个问题在哪里的方法倾销一切,我真的 需要打电话,因为这也是我检查的结果 调用了System.exit()。无论如何,我必须找到一种方法来测试这个。我 曾考虑过使用PowerMock和mocking系统,但那会 这很复杂,因为我必须找到确切的类调用 返回System.exit()。因此,这里有另一个解决方案来避免 System.exit到exit(是的,这是可能的,我不知道 要么)

    秘密在于Java的SecurityManager机制,这个类 不仅允许您检查权限,还允许您检查退出 事件因此,如果要停止该进程,可以抛出异常 出口

    下面是我在IJ测试的完整样本。请注意,该样品应故意不合格,原因如下:

    java.lang.AssertionError: 
    Expected: is <10>
         but: was <5>
    Expected :is <10>
    Actual   :<5>
    
    java.lang.AssertionError:
    预期:是吗
    但是:是吗
    预期:是吗
    实际:
    

    package.com.example;
    导入org.junit.Test;
    导入java.security.Permission;
    导入静态org.hamcrest.Matchers.is;
    导入静态org.junit.Assert.assertThat;
    导入静态org.junit.Assert.fail;
    公共类SystemExitSet{
    @试验
    公共无效应使用SpecificCode()退出{
    //保存初始安全管理器(可能为空)
    SecurityManager initialSecurityManger=System.getSecurityManager();
    试一试{
    //设置安全管理器
    System.setSecurityManager(新的NoExitSecurityManager());
    //执行测试中的代码
    新建MyClass()。退出(5);
    //确保这一点不是偶然达到的
    失败(“应该抛出ExitException”);
    }捕获(出口){
    //验证退出代码
    
    断言(E.Stand,(10));//我不认为这是一个好主意。你应该认真考虑重新设计你的系统,只调用你的main方法中的“代码>系统。退出< /代码>,没有别的地方。我不能改变这个代码,我必须在检查、Stuto.Ext()之后找到模拟问题的解决方案。仅在应用程序末尾的一个位置使用!不确定在调用System.exit()后,为什么会将测试显示为“Not started”(如上图所示)。当删除System.exit()时测试成功通过。所以你的问题已经解决了,不是吗?一点也没有。我已经编辑了这个问题。希望现在问题更清楚。非常确定很多ppl都将此作为调查的基础。我想这让我在这个主题上的研究减少了一半。干杯。
    org.powermock.reflect.exceptions.MethodNotFoundException: No method found with name 'exit' with parameter types: [ <none> ] in class java.lang.System.
    
    java.lang.AssertionError: 
    Expected: is <10>
         but: was <5>
    Expected :is <10>
    Actual   :<5>
    
    package com.example;
    
    import org.junit.Test;
    
    import java.security.Permission;
    
    import static org.hamcrest.Matchers.is;
    import static org.junit.Assert.assertThat;
    import static org.junit.Assert.fail;
    
    public class SystemExitTest {
    
        @Test
        public void shouldExitWithSpecificCode() {
            //save the initial security manager (probably null)
            SecurityManager initialSecurityManger = System.getSecurityManager();
            try {
                // set security manager
                System.setSecurityManager(new NoExitSecurityManager());
    
                // execute code under test
                new MyClass().exit(5);
    
                // ensure this point is not reached by any chance
                fail("Should've thrown ExitException");
            } catch (ExitException e) {
                // validate exit code
                assertThat(e.status, is(10)); // <== this fails on purpose
            } finally {
                // restore initial security manager (otherwise a new ExitException will be thrown when the JVM will actually exit)
                System.setSecurityManager(initialSecurityManger);
            }
        }
    
    
        // class under test
        public static class MyClass {
            public void exit(int code) {
                System.exit(code);
            }
        }
    
        // exception to be thrown by security manager when System.exit is called
        public static class ExitException extends SecurityException {
            public final int status;
    
            public ExitException(int status) {
                this.status = status;
            }
        }
    
    
        // custom security manager
        public static class NoExitSecurityManager extends SecurityManager {
            @Override
            public void checkPermission(Permission perm) {
            }
    
            @Override
            public void checkPermission(Permission perm, Object context) {
            }
    
            @Override
            public void checkExit(int status) {
                super.checkExit(status);
                throw new ExitException(status);
            }
        }
    }