今天的component有个commandline class需要测试main函数的返回值,我们知道正常情况下是无法测试commandline的类的,因为
public static final void main(String[] args) {}结束的时
候会调用system.exit(status).当然也会终止测试的jvm。也就是说如果我们直接这样写:
public void testStatus(){
CommandLineClass.main(args);
}
这是行不通的,一是你无法获得返回值,而是后边的语句和测试全部会被强行终止。当然任何难题都有解决的办法,我们知道main函数返回的系统调用exit,会经过securityManage的检查是否拥有权限。所以我们可以实现自己的securitymanager并覆写
checkExit(int status) 方法,保存status状态,这样就搞定了。简单吧?
这个是我刚才写的SecurityManager:
/**
* the mock security manager use for retrieve the exit status of the main method.
* <p>
* since the main method will call System.exit, we cannot make it executable with other tests because JVM
* will be halt once main() method is called. so we can "stop" and "ignore" the exit call execute.
* </p>
* @author netsafe
*/
class MockSecurityManager extends SecurityManager {
/**
* the status value of the exit method.
*/
private int status;
/**
* Throws a <code>SecurityException</code> if the calling thread is not allowed to cause the Java
* Virtual Machine to halt with the specified status code.
* <p>for this mock method,the SecurityException will always be thrown</p>
* @param status
* the exit status.
* @exception SecurityException
* if the calling thread does not have permission to halt the Java Virtual Machine with
* the specified status.
*/
@Override
public void checkExit(int status) {
this.status = status;
throw new SecurityException();
}
/**
* return the exit status.
* @return the exit status.
*/
public int getStatus() {
return status;
}
/**
* mock method for ignore the permission check.
* @param perm
* the requested permission.
*/
@Override
public void checkPermission(Permission perm) {
// does nothing
}
/**
* mock method for ignore the permission check.
* @param perm
* the specified permission
* @param context
* a system-dependent security context.
*/
@Override
public void checkPermission(Permission perm, Object context) {
// does nothing
}
}
这个是测试用的方法:
/**
* execute the CommandLineClass.main method and check the exit status.
* @param args
* the arguments for the main method
* @param expectedStatus
* the expected exit status
*/
private void assertExecuteStatus(String[] args, int expectedStatus) {
// backup the security manager.
SecurityManager oldManager = System.getSecurityManager();
MockSecurityManager manager = new MockSecurityManager();
System.setSecurityManager(manager);
try {
CommandLineClass.main(args);
} catch (SecurityException e) {
// ignore
}
assertEquals("the return status should be " + expectedStatus, expectedStatus, manager.getStatus());
// restore the security manager
System.setSecurityManager(oldManager);
}