JUnit测试控制台输出和System.exit(0)

JUnit测试中可以用assertTrue,assertEquals等断言对代码进行简单的测试:如返回的布尔类型是否为真,所得的数据结果是否与预想的一样,有时程序可能会为健壮性做一些向控制台输出和强制退出的操作,对于这样的功能用JUnit的断言可能不太直观,但实际上也是可行的。

这里以一个实现图的程序为例,Graph是一个图,可以通过addVertex操作向这张图中添加结点,对于同样名字的结点,addVertex方法会向控制台输出一句“名字重复”,并通过System.exit(0)的方式直接退出程序。
其中获得控制台的输出相对容易一些,只需要在控制台输出之前,将标准输出流指定到一个位置存储再进行比较就可以了:

private PrintStream console = null;
private ByteArrayOutputStream bytes = null;

@Before
public void setUp() {
	bytes = new ByteArrayOutputStream();// 把标准输出指定到ByteArrayOutputStream中
	console = System.out;// 获取System.out 输出流的句柄
	System.setOut(new PrintStream(bytes));// 将原本输出到控制台Console的字符流重定向到bytes
}

@After
public void tearDown() {
	System.setOut(console);
}

最后在@Test中将得到的控制台输出byte通过toString方法转化为字符串与预想结果“名字重复”进行比较就可以了。
这个过程中的问题是,由于程序输出完错误信息直接通过System.exit(0)退出,控制台被关闭,从而无法得到正确的结果,查阅资料后得知,System.exit其实会调用SecurityManager.checkPermission方法来校验权限,这个时候只要在checkPermission方法内部抛出一个异常,就能把System.exit后续的逻辑打断了,也就是不会退出了。
完整代码如下:

private PrintStream console = null;
private ByteArrayOutputStream bytes = null;

@Before
public void setUp() {
	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);
	bytes = new ByteArrayOutputStream();// 把标准输出指定到ByteArrayOutputStream中
	console = System.out;// 获取System.out 输出流的句柄
	System.setOut(new PrintStream(bytes));// 将原本输出到控制台Console的字符流重定向到bytes

}

@After
public void tearDown() {
	System.setOut(console);
}

@Test
public void testaddVertexRepeat() {
	try {
		Graph graph = new Graph();
		Vertex lee = new Vertex("lee");
		Vertex wong = new Vertex("lee");
		graph.addVertex(lee);
		graph.addVertex(wong);
	} catch (RuntimeException e) {

	} finally {
		System.setSecurityManager(null);
	}
	assertEquals("名字重复", bytes.toString());
}

参考资料

Junit System.exit测试的问题
Junit编写带有控制台输出的测试

发布了8 篇原创文章 · 获赞 3 · 访问量 298

猜你喜欢

转载自blog.csdn.net/weixin_43872188/article/details/104781255