简体   繁体   English

Robolectric无法使用启用的multidex运行测试

[英]Robolectric can not run test with enabled multidex

I am writing unit tests to cover API with tests. 我正在编写单元测试以涵盖测试的API。 I use robolectric and gradle, also have to add multidex to support large apk build. 我使用robolectric和gradle,还必须添加multidex以支持大型apk构建。 Unexpectedly I can not run the test and can not understand the stacktrace 没想到我无法运行测试并且无法理解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();
}

} }

Do you have an idea what is root cause? 您知道什么是根本原因吗?

Here is my gradle build 这是我的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'

UPDATE UPDATE

Console output: 控制台输出:

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"
    }
}

Please make sure you use Robolectric with the test ( not androidTest ) folders and the dependency should be likewise set with testCompile : 请确保您将Robolectric与test而非 androidTest )文件夹一起使用,并且依赖项也应使用testCompile进行设置:

 testCompile 'org.robolectric:robolectric:3.3.2' //don't use androidTestCompile here!!!

If you have problems with Robolectric, some steps to try include: 如果您在Robolectric方面遇到问题,请尝试一些步骤:

  1. Delete the .m2 folder to cause the dependencies from maven to be downloaded again 删除.m2文件夹,以使maven的依赖项重新下载
  2. Try refreshing gradle dependencies gradlew --refresh-dependencies and cleaning and rebuilding the project 尝试刷新gradle依赖关系gradlew --refresh-dependencies并清理和重建项目
  3. Make sure you have the latest jdk and delete the old jdks on your machine 确保您拥有最新的jdk并删除计算机上的旧jdk
  4. Make sure your tests are configured to run with the correct project dir 确保测试配置为以正确的项目目录运行
  5. Try adjusting your Robolectric test parameters: 尝试调整您的Robolectric测试参数:

     @RunWith(RobolectricGradleTestRunner.class) @Config(application = TestApplication.class, constants = BuildConfig.class, sdk = 21) 

You can try using RobolectricTestRunner.class instead of RobolectricGradleTestRunner.class and leaving out the @Config annotation. 您可以尝试使用RobolectricTestRunner.class而不是RobolectricGradleTestRunner.class@Config批注。 If that doesn't work, you can create a class: 如果这不起作用,则可以创建一个类:

public class EmptyApplication extends Application {
}

And use that: 并使用:

@Config(application = EmptyApplication.class)

Update : note the difference between a Robolectric test (in the test folder) and an Instrumented Android test (in the androidTest folder). 更新 :请注意Robolectric测试(在test文件夹中)和Instrumented Android测试(在androidTest文件夹中)之间的androidTest Robolectric tests are tests run in the IDE (on your computer's JVM) that simulate the Android classes (eg, Context ) available on a real device. Robolectric测试是在IDE(在您的计算机的JVM上)中运行的测试,它们模拟真实设备上可用的Android类(例如Context )。 Instrumented Android tests run on an Android handset or an emulator and use the real Context etc. from the Android SDK. 仪器化的Android测试在Android手机或仿真器上运行,并使用Android SDK中的真实 Context等。 The following is the example of an Instrumented test from an empty project: 以下是来自空项目的仪器化测试的示例:

package example.github.com.robolectricbug;

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
 * Instrumentation test, which will execute on an Android device.
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Test
    public void useAppContext() throws Exception {
        // Context of the app under test.
        Context appContext = InstrumentationRegistry.getTargetContext();

        assertEquals("example.github.com.robolectricbug", appContext.getPackageName());
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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