我的应用程序有一个流程,最后调用方法System.exit(int)
。
我试图通过使用TestNG运行测试来测试此流程。
但是,在运行测试时,虽然测试已完成,但我收到了这个奇怪的消息:
只是为了找到根本原因,我从实际流程中删除了System.exit(int)
并且测试按预期通过,所以这里的问题是System.exit(int)
方法。
为了解决这个问题,我试图模拟有问题的方法,但找不到正确的方法。这就是我做的
java.lang.System.class
下添加了@PrepareForTest
。PowerMockito.mockStatic(java.lang.System.class)
PowerMockito.replace(PowerMockito.method(System.class, "exit", int.class))
.with((proxy, method, args) -> null);
当以这种方式运行时看起来模拟不起作用,因为我在测试结束时得到相同的消息,当我在System.exit(int)上不应用任何模拟时我也得到了相同的消息湾
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)
它不起作用。
有任何想法吗?谢谢
有趣的问题,我也不知道,但显然通过使用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);
}
}
}