现象
在用junit做一个功能方法的时候,发现调用完功能方法后,后面的Assert断言根本就没有执行,junit测试用例既不显示红色的失败状态,也不显示绿色的通过状态,而是呈现出一种中途退出的现象。
分析
根据现象发现,原因很有可能是待测试的功能方法“意外退出”了,最有可能的是抛出了异常没有捕捉导致跳过了后面的断言逻辑,仔细检查了测试代码,发现并不是。仔细查看了待测功能方法,发现了猫腻,方法结束的时候会采用System.exit()的方式进行退出,那问题很有可能是这个引起的,对此进行了测试,测试代码如下:
@org.junit.Test
public void testSystemExit() {
System.out.println("start");
// 模拟功能方法中的退出
System.exit(0);
//查看退出了,是否会执行下面的代码
Assert.assertEquals(true, true);
System.out.println("end");
}
测试发现,果然System.exit(0);
后面的Assert.assertEquals(true, true);
和System.out.println("end");
都没有执行了。问题发现了,但是不能修改功能方法里的代码把所有的System.exit屏蔽掉,那只能从怎么把System.exit屏蔽掉的方面考虑了,经过一番google之后,发现了一篇文章 https://stackoverflow.com/questions/5401281/preventing-system-exit-from-api 里面提到System.exit其实会调用SecurityManager.checkPermission方法来校验权限,这个时候只要在checkPermission方法内部抛出一个异常,就能把System.exit后续的逻辑打断了,也就是不会退出了。 改造一下我们的junti用例
public class Test {
@Before
public void setUp() {
System.out.println("init");
final SecurityManager securityManager = new SecurityManager() {
public void checkPermission(Permission permission) {
/**
* 这里permission.getName()会返回exitVM. + status的形式
* 例如System.exit(0) 这里会是exitVM.0
* System.exit(1) 这里会是exitVM.1
* 这里不关系怎么退出的,只需要捕捉到,并不让他退出,继续运行我的测试代码就好了
*/
if (permission.getName().startsWith("exitVM")) {
throw new AccessControlException("");
}
}
};
System.setSecurityManager(securityManager);
}
@org.junit.Test
public void testSystemExit() {
System.out.println("start");
try {
// 模拟待测试的功能方法中的退出
System.exit(0);
} catch (RuntimeException e) {
// do nothing
} finally {
// 屏蔽好之后,重新设置setSecurityManager为Null,防止junit退出的时候报错
System.setSecurityManager(null);
}
//查看退出了,是否会执行下面的代码
Assert.assertEquals(true, true);
System.out.println("end");
}
}
这样就能进行Junit测试了,也不会破坏待测试方法的功能逻辑。