[英]IOException from Runtime.getRuntime().exec() not caught by Android JUnit
我正在尝试在Android设备上测试某些需要root权限的命令的执行情况。 在没有超级用户应用程序的情况下,出现permission denied
错误,导致尝试写入进程的输出流时引发IOException。
但是,该异常虽然在通过调试器进行调试时是可见的,但它既不会被JUnit拦截(因此测试以错误结束),也无法被调试器检测到以暂停执行。
例外在哪里去了? 如何修复测试,以便异常导致JUnit中的错误?
这是我的测试:
String[] PWD = new String[] { "pwd" };
@Test
public void testSudoForResult() throws IOException {
// this should throw IOException:
String result = SudoHelper.sudoForResult(PWD);
// these assertions are evaluated though they should not be, due to an error in the line above
assertNotNull(result);
assertTrue(result.length() > 0); // this assertion fails
}
以及正在测试的代码:
public static String sudoForResult(String... commands) throws IOException {
List<String> allCommands = new ArrayList<>(commands.length+1);
allCommands.addAll(Arrays.asList(commands));
allCommands.add("exit");
return execForResult("/system/xbin/su", allCommands.toArray(new String[0]));
}
private static String execForResult(String command, String... strings) throws IOException {
String res = "";
DataOutputStream outputStream = null;
InputStream response = null;
InputStream errorStream = null;
String s = null;
try {
Process su = Runtime.getRuntime().exec(command);
response = su.getInputStream();
errorStream = su.getErrorStream();
if (strings != null) {
outputStream = new DataOutputStream(su.getOutputStream());
for (int i = 0; i < strings.length; i++) {
s = strings[i];
outputStream.writeBytes(s + "\n");
outputStream.flush();
}
}
try {
su.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
res = readFully(response);
} catch (IOException e) {
// I can step in here with a debugger, but it won't suspend when I put a breakpoint here
// The exception won't get caught by JUnit, even if I remove this catch block.
if (errorStream != null) {
// As expected, this will contain the message "Permission denied", due to the lack of Superuser app in my test case:
String errors = readFully(errorStream);
Log.e(TAG, "Error while processing command:" + s +": "+errors, e);
}
throw e;
} finally {
FileUtils.quietlyClose(outputStream);
FileUtils.quietlyClose(response);
}
return res;
}
public static String readFully(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ((length = is.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return baos.toString("UTF-8");
}
更新:我可以在调试时看到以下行为。 离开了finally
块之后,我进入了org.junit.internal.runners.model.ReflectveCallable#run()
的catch块中,带有一个InvokationTargetException
,其原因是我的IOException
。 然后,它沿Runner
的结构传播,由EachTestNotifier#addFailure
消耗,似乎报告了失败,但没有报告。
您可以在调用SudoHelper.sudoForResult(PWD)
的区域周围放置一个try/catch
块。 否则,您和JUnit都不会处理该异常,因为调用testSudoForResult
方法时JUnit不会处理该异常。 该程序将崩溃,因此“未处理”代码之后的代码将无法运行。
为了解决这个问题,代码可能看起来像这样:
@Test
public void testSudoForResult() /* no throwing exceptions here! */ {
String result = "";
try {
result = SudoHelper.sudoForResult(PWD);
} catch(IOException ex) {
//handle exception however you want, maybe with e.printStackTrace()
}
assertNotNull(result);
assertTrue(result.length() > 0);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.