我正在尝试测试给定的 java 应用程序,为此我想使用 JUnit。
我面临的问题如下:一旦我尝试测试的代码完成它的工作,它的调用System.exit()
就会关闭应用程序。虽然它也阻止了我的测试完成,因为它关闭了 JVM(我假设)。
有没有办法在不修改原始代码的情况下解决这个问题?最初我尝试从新线程启动应用程序即时测试,尽管这显然没有太大区别。
您可以使用系统规则:“用于测试代码的 JUnit 规则集合java.lang.System
。”
在他们的规则中,你有ExpectedSystemExit
,下面是一个如何使用它的例子。我相信这是一个非常干净的解决方案。
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.Assertion;
import org.junit.contrib.java.lang.system.ExpectedSystemExit;
public class SystemExitTest {
@Rule
public final ExpectedSystemExit exit = ExpectedSystemExit.none();
@Test
public void noSystemExit() {
//passes
}
@Test
public void executeSomeCodeAFTERsystemExit() {
System.out.println("This is executed before everything.");
exit.expectSystemExit();
exit.checkAssertionAfterwards(new Assertion() {
@Override
public void checkAssertion() throws Exception {
System.out.println("This is executed AFTER System.exit()"+
" and, if exists, the @org.junit.After annotated method!");
}
});
System.out.println("This is executed right before System.exit().");
System.exit(0);
System.out.println("This is NEVER executed.");
}
@Test
public void systemExitWithArbitraryStatusCode() {
exit.expectSystemExit();
System.exit(0);
}
@Test
public void systemExitWithSelectedStatusCode0() {
exit.expectSystemExitWithStatus(0);
System.exit(0);
}
@Test
public void failSystemExit() {
exit.expectSystemExit();
//System.exit(0);
}
}
如果您使用 Maven,您可以将其添加到您的pom.xml
:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>1.3.0</version>
</dependency>
System.exit(status)
实际上将调用委托给Runtime类。继续此关闭请求之前的运行时checkExit(status)
调用JVM 的当前SecurityManager可以通过抛出SecurityException来防止即将关闭。
通常,SecurityManager需要确定当前线程是否具有由当前安全策略定义的关闭权限,但由于我们需要从这个退出调用中恢复,我们只需抛出一个SecurityException,我们现在必须捕获它我们的 JUnit 测试用例。
在您的 JUnit 测试类中,在方法中设置一个SecurityManagersetUP()
:
securityManager = System.getSecurityManager();
System.setSecurityManager(new SecurityManager() {
@Override
public void checkExit(int status) {
super.checkExit(status); // This is IMPORTANT!
throw new SecurityException("Overriding shutdown...");
}
});
再次将SecurityManagertearDown()
替换为我们之前保存的实例。不这样做会阻止 JUnit 现在关闭!:)
参考资料: http:
//docs.oracle.com/javase/1.5.0/docs/api/java/lang/SecurityManager.html
http://docs.oracle.com/javase/1.5.0/docs/api/java /lang/SecurityManager.html#checkExit(int)
SecurityManager 类包含许多名称以单词 check 开头的方法。在这些方法执行某些潜在敏感操作之前,这些方法由 Java 库中的各种方法调用。这种检查方法的调用通常如下所示:
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkXXX(argument, . . . );
}
因此,安全管理器有机会通过抛出异常来阻止操作完成。如果操作被允许,安全管理器例程会简单地返回,但如果操作不被允许,则抛出 SecurityException。
System.exit() 除了调用应用程序作为单独的进程(在您的 JVM 之外)运行之外,没有其他办法。
您可以从单元测试中执行此操作,并观察从它返回的错误级别。这是否对通过测试提供足够的反馈取决于您的判断。