【发布时间】:2017-04-23 11:22:19
【问题描述】:
我正在编写单元测试来覆盖带有测试的 API。我使用 robolectric 和 gradle,还必须添加 multidex 以支持大型 apk 构建。没想到无法运行测试,也看不懂stacktrace
java.lang.NullPointerException: parentLoader == null && !nullAllowed
at java.lang.ClassLoader.<init>(ClassLoader.java:210)
at java.lang.ClassLoader.<init>(ClassLoader.java:202)
at java.security.SecureClassLoader.<init>(SecureClassLoader.java:48)
at java.net.URLClassLoader.<init>(URLClassLoader.java:710)
at java.net.URLClassLoader.<init>(URLClassLoader.java:555)
at org.codehaus.classworlds.RealmClassLoader.<init>(RealmClassLoader.java:94)
at org.codehaus.classworlds.RealmClassLoader.<init>(RealmClassLoader.java:83)
at org.codehaus.classworlds.DefaultClassRealm.<init>(DefaultClassRealm.java:116)
at org.codehaus.classworlds.ClassWorld.newRealm(ClassWorld.java:100)
at org.apache.maven.artifact.ant.AbstractArtifactTask.getContainer(AbstractArtifactTask.java:490)
at org.apache.maven.artifact.ant.AbstractArtifactTask.lookup(AbstractArtifactTask.java:457)
at org.apache.maven.artifact.ant.AbstractArtifactTask.initSettings(AbstractArtifactTask.java:290)
at org.apache.maven.artifact.ant.AbstractArtifactTask.execute(AbstractArtifactTask.java:750)
at org.robolectric.internal.dependency.MavenDependencyResolver.getLocalArtifactUrls(MavenDependencyResolver.java:40)
at org.robolectric.internal.dependency.CachedDependencyResolver.getLocalArtifactUrls(CachedDependencyResolver.java:43)
at org.robolectric.internal.InstrumentingClassLoaderFactory.getSdkEnvironment(InstrumentingClassLoaderFactory.java:39)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:187)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:59)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:262)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1837)
@RunWith(RobolectricGradleTestRunner.class)
@Config(application = TestApplication.class,
constants = BuildConfig.class,
sdk = 21)
public class ApiTest {
private MockWebServer webServer;
private IApi api;
private TestUtils testUtils;
@Before
public void setUp() throws Exception {
Log.d(App.TAG, "Test setUp");
testUtils = new TestUtils();
webServer = new MockWebServer();
webServer.start();
webServer.setDispatcher(new Dispatcher() {
@Override
public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
MockResponse response;
if (request.getPath().equals("savingsgoals")) {
response = new MockResponse().setResponseCode(200)
.setBody(testUtils.readString("json/goals.json"));
} else if (request.getPath().equals("savingsgoals/" + TestApp.Const.GOAL_ID + "/feed")) {
response = new MockResponse().setResponseCode(200)
.setBody(testUtils.readString("json/feed.json"));
} else if (request.getPath().equals("savingsrules")) {
response = new MockResponse().setResponseCode(200)
.setBody(testUtils.readString("json/rules.json"));
} else if (request.getPath().equals("user/" + TestApp.Const.USER_ID)) {
response = new MockResponse().setResponseCode(200)
.setBody(testUtils.readString("json/user.json"));
} else {
response = new MockResponse().setResponseCode(404);
}
return response;
}
});
HttpUrl url = webServer.url("/");
api = ApiModule.getApiInterface(url.toString());
}
@Test
public void testGoals() throws Exception {
TestSubscriber<SavingsGoals> testSubscriber = new TestSubscriber();
api.getSavingsGoals().subscribe(testSubscriber);
testSubscriber.assertNoErrors();
testSubscriber.assertValueCount(1);
SavingsGoals goals = testSubscriber.getOnNextEvents().get(0);
goals.getSavingsGoals();
}
}
您知道根本原因是什么吗?
这是我的 gradle 构建
androidTestCompile 'org.robolectric:robolectric:3.3.2'
androidTestCompile('com.squareup.okhttp:mockwebserver:2.7.0', {
exclude group: 'com.squareup.okio', module: 'okio'
})
androidTestCompile 'junit:junit:4.12'
更新
控制台输出:
Error:Execution failed for task ':app:transformClassesWithDexForDebugAndroidTest'. > com.android.build.api.transform.TransformException: java.lang.RuntimeException: java.lang.RuntimeException: Unable to pre-dex 'D:\Users\John\.gradle\caches\modules-2\files-2.1\com.thoughtworks.xstream\xstream\1.4.8\520d90f30f36a0d6ba2dc929d980831631ad6a92\xstream-1.4.8.jar' to 'C:\workspace\TestRobolectricTest\app\build\intermediates\pre-dexed\androidTest\debug\xstream-1.4.8_54d21a03bcf95b493d9c102453945dde45691be3.jar'
allprojects {
tasks.withType(JavaCompile) {
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
}
}
【问题讨论】:
-
您使用的不是最新版本的 Robolectric。尝试升级到最新版本
-
事实上很多依赖已经过时了,Dagger 已经在
2.10并且Mockito 已经达到了2.7.22版本。我建议尝试花一些时间更新依赖项,然后看看是否可以重现问题。完成此操作后,要尝试的另一件事是删除缓存 Robolectric 依赖项的.m2文件夹(在运行时从 Maven 下载)并尝试gradlew --refresh-dependencies。你可以从不匹配的 .jars 中得到类似的错误 -
花时间回到这个话题。我更新了所有依赖项并清理了缓存。仍然无法运行代码,但现在有另一个问题(请参阅更新部分),似乎某些模块的字节码与其他模块不兼容(java 1.7 vs 1.8)。我应用了应该提供与输出相同的字节码的任务,但问题仍然存在。你有什么想法为什么会发生?
-
很好地更新了依赖项。你能在这里试试这个答案吗stackoverflow.com/a/33653063/5241933
-
没有帮助,同样的问题。我将可能问题的范围缩小到几个依赖项——添加 robolectric 会产生问题。您能否在您身边创建示例项目并尝试使用这两个依赖项运行测试?只是想确认这不是我的环境的问题
标签: android automated-tests robolectric dagger-2