无法使用PowerMock模拟java.lang.System#exit(int)方法

问题描述 投票:2回答:1

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

我试图通过使用TestNG运行测试来测试此流程。

但是,在运行测试时,虽然测试已完成,但我收到了这个奇怪的消息:

enter image description here

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

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

  1. 我在测试课中在java.lang.System.class下添加了@PrepareForTest
  2. 在测试中添加了PowerMockito.mockStatic(java.lang.System.class)
  3. 我试图以两种方式模拟该方法: 一个。 PowerMockito.replace(PowerMockito.method(System.class, "exit", int.class)) .with((proxy, method, args) -> null); 当以这种方式运行时看起来模拟不起作用,因为我在测试结束时得到相同的消息,当我在System.exit(int)上不应用任何模拟时我也得到了相同的消息

enter image description here

PowerMockito.doNothing().when(System.class, "exit", Mockito.any());

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

org.powermock.reflect.exceptions.MethodNotFoundException: No method found with name 'exit' with parameter types: [ <none> ] in class java.lang.System.

我已经用这种方式嘲笑了一些方法,不知道为什么用System.exit(int)它不起作用。

有任何想法吗?谢谢

java testng powermock powermockito
1个回答
0
投票

有趣的问题,我也不知道,但显然通过使用SecurityManagers可以在不使用Powermock的情况下实现这一点。引自original post

今天我正在为我们的一个命令行工具编写测试,我遇到了这个问题,其中方法转储所有内容,我真的需要调用,因为这是我正在检查的结果,也称为System.exit()。无论如何,我必须找到一种测试方法。我想过使用PowerMock和mocking系统,但这本来很复杂,因为我必须找到调用System.exit()的确切类。所以这是避免System.exit退出的另一个解决方案(是的,我可能也不知道这个)。

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

以下是我在IJ测试的完整样本。请注意,样本应该故意失败:

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);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.