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

Java Android JUnit未捕获Runtime.getRuntime().exec()中的IOException,java,android,junit,Java,Android,Junit,我试图在Android设备上测试一些需要root权限的命令的执行情况。由于没有超级用户应用程序,我得到了一个权限被拒绝错误,导致在尝试写入进程的输出流时引发IOException,这很好 但是,该异常虽然在使用调试器进行切换时可见,但JUnit既不会截获(因此测试以错误结束),也不会被调试器检测到以暂停执行 例外情况到哪里去了?如何修复测试,使异常在JUnit中导致错误 这是我的测试: String[] PWD = new String[] { "pwd" }; @Test public voi

我试图在Android设备上测试一些需要root权限的命令的执行情况。由于没有超级用户应用程序,我得到了一个
权限被拒绝
错误,导致在尝试写入进程的输出流时引发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");
}
公共静态字符串sudoForResult(字符串…命令)引发IOException{
List allCommands=newarraylist(commands.length+1);
addAll(Arrays.asList(commands));
添加(“退出”);
返回execForResult(“/system/xbin/su”,allCommands.toArray(新字符串[0]);
}
私有静态字符串execForResult(字符串命令、字符串…字符串)引发IOException{
字符串res=“”;
DataOutputStream outputStream=null;
InputStream响应=null;
InputStream errorStream=null;
字符串s=null;
试一试{
进程su=Runtime.getRuntime().exec(命令);
response=su.getInputStream();
errorStream=su.getErrorStream();
if(字符串!=null){
outputStream=新的DataOutputStream(su.getOutputStream());
for(int i=0;i

更新:调试时我可以看到以下行为。在离开
finally
块后,我进入了一个catch块
org.junit.internal.runners.model.ReflectveCallable#run()
,其中有一个
InvokationTargetException
,其原因是我的
IOException
。然后它被传播到
Runner
的结构中,在那里它被
EachTestNotifier#addFailure
使用,它似乎报告了失败,但它没有。你可以在调用
SudoHelper.sudoForResult(PWD)
的区域周围放置一个
try/catch
块。否则,异常不由您和JUnit处理,因为JUnit在调用
testSudoForResult
方法时不处理异常。程序将崩溃,因此“未处理”代码之后的代码将不会运行

要解决此问题,代码可能更像这样:

@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);
}

您可以在调用
SudoHelper.sudoForResult(PWD)
的区域周围放置一个
try/catch
块。否则,异常不由您和JUnit处理,因为JUnit在调用
testSudoForResult
方法时不处理异常。程序将崩溃,因此“未处理”代码之后的代码将不会运行

要解决此问题,代码可能更像这样:

@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);
}

我希望在抛出异常时测试失败。我已经尝试过这个解决方案,在catch块中调用了
fail()。不幸的是,它也没有被调用。我希望在抛出异常时测试失败。我已经尝试过这个解决方案,在catch块中调用了
fail()。不幸的是,它也没有被调用。