无法使用 PowerMock 模拟 java.lang.System#exit(int) 方法 [英] Can't mock java.lang.System#exit(int) method with PowerMock

查看:106
本文介绍了无法使用 PowerMock 模拟 java.lang.System#exit(int) 方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My application has a flow that in the end of it the method System.exit(int) is being called.

我正在尝试通过使用 TestNG 运行测试来测试此流程.

I'm trying to test this flow by running a test using TestNG.

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

However, when running the test I'm getting this weird message although the test was completed:

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

Just for finding the root cause, I removed the System.exit(int) from the real flow and the test passed as expected, so the problem here is the System.exit(int) method.

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

In order to solve this issue I've tried to mock the problematic method but couldn't find the right way to do it. Here is what I did

  1. 我在测试类的 @PrepareForTest 下添加了 java.lang.System.class.
  2. 在测试中添加了PowerMockito.mockStatic(java.lang.System.class)
  3. 我尝试以两种方式模拟该方法:

  1. I added java.lang.System.class under @PrepareForTest in the tests class.
  2. added PowerMockito.mockStatic(java.lang.System.class) in the test
  3. I've tried to mock the method in two ways:

一个.

    PowerMockito.replace(PowerMockito.method(System.class, "exit", int.class))
    .with((proxy, method, args) -> null);

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

When running this way looks like the mock is not working, because I'm getting the same message at the end of the test which I also got when not applying any mocks on System.exit(int)

B.

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

通过这种方式,我在测试开始时收到此异常:

In this way I'm getting this exception at the beginning of the test:

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

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

I already mocked some methods in this ways, not sure why with System.exit(int) it is not working.

有什么想法吗?谢谢

推荐答案

有趣的问题,我也不知道,但显然,通过使用 SecurityManagers,无需使用 Powermock 即可实现.引用原帖:

Interesting question, I didn't know either, but apparently this is possible without the use of Powermock, through the use of SecurityManagers. Quoting from the original post:

今天我正在为我们的一个命令行工具编写测试,我有这个问题的方法倾倒了一切,我真的需要被调用,因为这是我正在检查的结果,也是称为 System.exit().无论如何,我必须找到一种方法来测试它.一世考虑过使用 PowerMock 和模拟系统,但这会很复杂,因为我必须找到确切的类调用System.exit().所以这里是另一种解决方案,以避免System.exit 退出(是的,这可能我不知道或者).

Today I was writing test for one of our command line tools, and I had this problem where the method dumping everything, which I really needed to be called since that’s the outcome I was checking, also called System.exit(). I had to find a way to test this anyway. I thought about using PowerMock and mocking system but that would have been complicated because I would have to find the exact class calling the System.exit(). So here is another solution to avoid the System.exit to exit (yes that’s possible I didn’t know about that either).

秘密在于Java的SecurityManager机制,这个类不仅可以让您检查权限,还可以检查退出事件.因此,如果您想停止退出

The secrets lays in the SecurityManager mechanism of Java, this class not only allows you to check permissions, but also to check exit event. Therefore you can throw an exception if you want to stop the exit

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

Below is a full sample I tested in IJ. Please note the sample is supposed to fail on purpose with:

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);
        }
    }
}

这篇关于无法使用 PowerMock 模拟 java.lang.System#exit(int) 方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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