使用Robotium测试无源码APK时启动失败,遇InitializerError
解决Robotium黑盒测试中的InitializerError问题
我看到你在用Android Studio 3.1.2 + Robotium对无源码的APK做黑盒测试时遇到了InitializerError,先帮你梳理下当前的代码配置和错误,再给出针对性的修复方案。
一、当前测试代码与配置
1. Robotium测试类代码
import android.test.ActivityInstrumentationTestCase2; import android.util.Log; import com.robotium.solo.Solo; @SuppressWarnings("rawtypes") public class RobotiumTest extends ActivityInstrumentationTestCase2 { private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME = "com.example.hqsg.activities.HQSoundGuideActivity"; private static Class launcherActivityClass; static { try { launcherActivityClass = Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new RuntimeException(e); } } public RobotiumTest() throws ClassNotFoundException { super(launcherActivityClass); } private Solo mDevice; @Override public void setUp() throws Exception { mDevice = new Solo(getInstrumentation(), getActivity()); super.setUp(); } @Override public void tearDown() throws Exception { mDevice.finishOpenedActivities(); super.tearDown(); } public void test() { mDevice.clickOnButton(0); } }
2. Manifest配置
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.robotium"> <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <uses-library android:name="android.test.runner" /> </application> </manifest>
3. Gradle配置
apply plugin: 'com.android.application' android { signingConfigs { config { keyAlias 'androiddebugkey' keyPassword 'android' storeFile file('C:/Users/suman_A/Desktop/key.jks') storePassword 'android' } } compileSdkVersion 27 defaultConfig { applicationId "com.example.robotium" minSdkVersion 15 targetSdkVersion 27 versionCode 1 versionName "1.0" testApplicationId 'com.example.hqsg' testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" signingConfig signingConfigs.config multiDexEnabled true } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { signingConfig signingConfigs.config } } testOptions { unitTests.returnDefaultValues = true } buildToolsVersion '27.0.3' } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.0' debugImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support:support-annotations:27.1.1' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:rules:1.0.2' implementation 'com.jayway.android.robotium:robotium:5.6.1' androidTestImplementation 'com.jayway.android.robotium:robotium-solo:5.6.1' implementation 'com.squareup.okhttp3:okhttp:3.10.0' implementation 'com.android.support:multidex:1.0.3' }
二、遇到的错误信息
java.lang.ExceptionInInitializerError at java.lang.reflect.Constructor.newInstance0(Native Method) at java.lang.reflect.Constructor.newInstance(Constructor.java:430) at junit.framework.TestSuite.createTest(TestSuite.java:61) at junit.framework.TestSuite.addTestMethod(TestSuite.java:294) at junit.framework.TestSuite.addTestsFromTestCase(TestSuite.java:150) at junit.framework.TestSuite.<init>(TestSuite.java:129) at android.support.test.internal.runner.junit3.NonLeakyTestSuite.<init>(NonLeakyTestSuite.java:33) at android.support.test.internal.runner.junit3.AndroidTestSuite.<init>(AndroidTestSuite.java:46) at android.support.test.internal.runner.junit3.AndroidJUnit3Builder.runnerForClass(AndroidJUnit3Builder.java:87) at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59) at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26) at android.support.test.internal.runner.AndroidRunnerBuilder.runnerForClass(AndroidRunnerBuilder.java:153) at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59) at android.support.test.internal.runner.TestLoader.doCreateRunner(TestLoader.java:73) at android.support.test.internal.runner.TestLoader.getRunnersFor(TestLoader.java:104) at android.support.test.internal.runner.TestRequestBuilder.build(TestRequestBuilder.java:789) at android.support.test.runner.AndroidJUnitRunner.buildRequest(Andro
三、问题分析与修复方案
ExceptionInInitializerError一般是静态代码块执行失败导致的,看你的测试类静态块里是在加载目标APK的启动Activity类,这里大概率是目标APK的类没有被正确加载,或者测试应用的配置有问题,针对你的场景,给你几个修复步骤:
1. 修正测试类的继承与构造方法
ActivityInstrumentationTestCase2是JUnit3的类,而你用的AndroidJUnitRunner是JUnit4的 runner,两者混用容易出问题。建议调整测试类结构:
public class RobotiumTest extends ActivityInstrumentationTestCase2 { private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME = "com.example.hqsg.activities.HQSoundGuideActivity"; private static Class<?> launcherActivityClass; static { try { launcherActivityClass = Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME); } catch (ClassNotFoundException e) { throw new RuntimeException("Could not load target activity class", e); } } public RobotiumTest() { super(launcherActivityClass); } // ... 其他代码不变 }
这里去掉构造方法的throws ClassNotFoundException,因为静态块已经处理了异常,避免重复抛出。
2. 修正Gradle中的测试配置
- 你当前把
robotium依赖放在了implementation,应该只放在androidTestImplementation,因为测试库不需要打包到主应用里:
// 移除这行 // implementation 'com.jayway.android.robotium:robotium:5.6.1' androidTestImplementation 'com.jayway.android.robotium:robotium-solo:5.6.1'
testApplicationId需要设置为测试应用的包名后缀,而不是目标APK的包名,否则会导致类加载冲突:
defaultConfig { // ... 其他配置 testApplicationId "com.example.robotium.test" }
3. 确保目标APK已正确安装且签名一致
黑盒测试时,测试应用和目标APK必须使用相同的签名,否则无法获取目标应用的权限。如果目标APK是debug签名,建议你把测试应用的debug签名改成默认的debug签名,避免签名不匹配。
4. 调整Manifest配置
添加instrumentation节点指定目标包名,这是黑盒测试的必要配置:
<manifest ...> <!-- 已有的权限和application节点 --> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.hqsg" /> </manifest>
这个节点告诉测试runner要测试的目标应用包名,没有的话会找不到目标Activity。
5. 修正setUp方法的执行顺序
setUp方法里应该先调用super.setUp(),再初始化Solo,因为getActivity()需要在父类初始化之后才能获取到:
@Override public void setUp() throws Exception { super.setUp(); mDevice = new Solo(getInstrumentation(), getActivity()); }
四、验证步骤
- 确保目标APK已经安装在测试设备/模拟器上;
- 重新同步Gradle,清理并重建测试项目;
- 运行测试类,看是否能正常启动目标应用并执行测试。
内容的提问来源于stack exchange,提问作者Suman Ankali
相关产品推荐
相关产品推荐

