繁体   English   中英

Android JUnit未捕获Runtime.getRuntime()。exec()的IOException

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM