簡體   English   中英

Robolectric無法使用啟用的multidex運行測試

[英]Robolectric can not run test with enabled multidex

我正在編寫單元測試以涵蓋測試的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'

UPDATE

控制台輸出:

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與test而非 androidTest )文件夾一起使用,並且依賴項也應使用testCompile進行設置:

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

如果您在Robolectric方面遇到問題,請嘗試一些步驟:

  1. 刪除.m2文件夾,以使maven的依賴項重新下載
  2. 嘗試刷新gradle依賴關系gradlew --refresh-dependencies並清理和重建項目
  3. 確保您擁有最新的jdk並刪除計算機上的舊jdk
  4. 確保測試配置為以正確的項目目錄運行
  5. 嘗試調整您的Robolectric測試參數:

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

您可以嘗試使用RobolectricTestRunner.class而不是RobolectricGradleTestRunner.class@Config批注。 如果這不起作用,則可以創建一個類:

public class EmptyApplication extends Application {
}

並使用:

@Config(application = EmptyApplication.class)

更新 :請注意Robolectric測試(在test文件夾中)和Instrumented Android測試(在androidTest文件夾中)之間的androidTest Robolectric測試是在IDE(在您的計算機的JVM上)中運行的測試,它們模擬真實設備上可用的Android類(例如Context )。 儀器化的Android測試在Android手機或仿真器上運行,並使用Android SDK中的真實 Context等。 以下是來自空項目的儀器化測試的示例:

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