我正在尝试测试某些需要在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()
的一个区块中,其中InvokationTargetException
的原因是IOException
。然后它会传播到Runner
的结构上,EachTestNotifier#addFailure
消耗它,它似乎报告失败,但事实并非如此。
答案 0 :(得分:0)
您可以在try/catch
调用的区域周围放置一个SudoHelper.sudoForResult(PWD)
块。否则,您和JUnit不会处理异常,因为JUnit在调用testSudoForResult
方法时不会处理异常。程序将崩溃,因此代码在&#34;未处理的&#34;之后代码不会运行。
要解决此问题,代码可能看起来更像这样:
@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);
}