首页 > 代码库 > Test run failed: Instrumentation run failed due to 'Process crashed.'解析
Test run failed: Instrumentation run failed due to 'Process crashed.'解析
在使用基于Instrumentation测试框架如robotium时,Test run failed: Instrumentation run failed due to ‘Process crashed.‘这个报错估计大多数人都遇到过,Android的应用是以Linux进程的概念在运行的,而Instrumentation与被测应用运行在同一个进程中,当被测应用的进程在Instrumentation本身退出前被关闭了,则会抛出Test run failed: Instrumentation run failed due to ‘Process crashed.‘这样的错误。
测试过程中引起这种情况的主要有两大类:
一、被测工程或测试工程本身代码运行异常导致
这类比较好办,首先手动运行被测的应用,没问题的话就可以排除了。然后看看运行时的错误日志,检查下测试工程的配置之类,一般就可以很快定位到。
二、被测应用的主Activity在调用onDestory()方法时有调用如android.os.Process.killProcess(android.os.Process.myPid())或System.exit(0)这种退出进程的方法
这种情况应该是大多数导致Test run failed: Instrumentation run failed due to ‘Process crashed.‘的原因
Android应用中基本都会有个主入口的Activity,即应用的启动页,先看看我们常见的“再按一次退出程序”的实现:
/** * 返回键退出应用 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN){ if((System.currentTimeMillis()-exitTime) > 2000){ Toast.makeText(getApplicationContext(), "再按一次退出程序", Toast.LENGTH_SHORT).show(); exitTime = System.currentTimeMillis(); } else { finish(); System.exit(0); } return true; } return super.onKeyDown(keyCode, event); }
有些应用是按一次返回键就退出程序了,但道理都是一样的,即应用的主Activity会去监听KEYCODE_BACK事件,当我们点击BACK键时,程序调用System.exit(0)或android.os.Process.killProcess(android.os.Process.myPid())退出程序。
如果你的应用是类似这种实现,那么测试时一般就不会碰到Instrumentation run failed due to ‘Process crashed.问题了。
如果你的应用是只要当前Activity被销毁,即在onDestory()方法中调用System.exit(0)的话,且你的测试用例在tearDown()时调用了solo.finishOpenedActivities()方法,且你的测试用例调起了主入口的Activity,由于finishOpenedActivities()会将所有已打开过的Activity都销毁,那么主入口Activity也会被销毁,而Activity被销毁时会调用onDestory()方法,那么此种情况必然每次都会报这个错。
这种情况下网上有的会说在tearDown()时别调用finishOpenedActivities()方法,这显然是不可行的,因为这会使多个测试用例执行时卡住不能往下执行,因为基于Instrumentation的测试框架,生命周期为setUp()——>以test开头的测试方法——>tearDown()
setUp()时会把被测的Activity调起,并做一些初始化相关,然后执行测试方法,最后tearDown()清理数据等,为了保障每个用例尽可能地可靠、稳定、具有原子性,这种框架的生命周期还是得遵守的。
解决办法的话,只能是让开发修改退出程序的方式,不要在主Activity的onDestory()时直接调用System.exit(0)。
其它:当连续执行几百个测试用例时,有时正常、有时又会偶然性地出现Test run failed: Instrumentation run failed due to ‘Process crashed.‘问题
由上文可知被测应用的主Activity会监听KEYCODE_BACK事件,当你的用例有调起过或测试过程中会经过主Activity时,那么任何带有KEYCODE_BACK的事件都有可能导致报这个错。
在robotium中会发送KEYCODE_BACK的主要用以下两个方法:
一个是goBack()方法:
/** * Simulates pressing the hardware back key. */ public void goBack() { sleeper.sleep(); try { inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK); sleeper.sleep(); } catch (Throwable ignored) {} }对于偶然性地出现这个报错,测试用例中应该不会有人没事老调用goBack()方法,因此应该不会是由于这个引起的。
另一个就是每个用例都会用到的finishOpenedActivities()方法:
/** * All activites that have been opened are finished. */ public void finishOpenedActivities(){ // Stops the activityStack listener activitySyncTimer.cancel(); ArrayList<Activity> activitiesOpened = getAllOpenedActivities(); // Finish all opened activities for (int i = activitiesOpened.size()-1; i >= 0; i--) { sleeper.sleep(MINISLEEP); finishActivity(activitiesOpened.get(i)); } activitiesOpened = null; sleeper.sleep(MINISLEEP); // Finish the initial activity, pressing Back for good measure finishActivity(getCurrentActivity(true, false)); setRegisterActivities(false); this.activity = null; sleeper.sleepMini(); try { inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK); sleeper.sleep(MINISLEEP); inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK); } catch (Throwable ignored) { // Guard against lack of INJECT_EVENT permission } clearActivityStack(); }
由上可知源码的作者在把所有的已打开的Activity都关闭后,还调用了两次inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
其实正常情况下前半段代码就已经能够把所有的已打开的Activity都关闭了,但出于某些特殊情况的考虑,可能在那个for循环中并没能将已打开的Activity均关闭,所以作者还特意多调用了两次KEYCODE_BACK,而这也就带来了较大的出现Instrumentation run failed due to ‘Process crashed.‘的风险。
解决的话比如可以在inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK)前增加判断当前的Activity是否是你应用的主Activity
Test run failed: Instrumentation run failed due to 'Process crashed.'解析