问题 如何在Gradle中指定类路径排序


我需要在testRuntime配置中控制jar的顺序。

我必须确保robolectric-x.x.jar在android.jar之前,否则我得到了可怕的RuntimeException(“Stub!”)。

我怎么做?


4876
2017-08-29 08:57


起源

是否在文档中说robolectric jar必须在类路径上的android.jar之前? - c_maker
是的,它确实。从Robolectric主页:“疑难解答java.lang.RuntimeException:Stub!确保robolectric及其依赖项出现在类路径中的Android API jar之前。” - Olle Hallin
它适用于Eclipse,因为可以在那里显式控制类路径的顺序。 Eclipse项目由Gradle生成。 - Olle Hallin
您可以通过gradle依赖关系中的顺序来解决它,但要注意两个具有更高优先级的规则! stackoverflow.com/a/38743046/715269 - Gangnus


答案:


这是我的完整 的build.gradle 对我使用RoboGuice的Android应用程序运行Robolectric测试:

apply plugin: 'java'

androidJar = new File(System.getenv('ANDROID_HOME'), '/platforms/android-7/android.jar')

configurations { robo }

dependencies {
    robo('com.pivotallabs:robolectric:1.0-RC1')
    testCompile('org.roboguice:roboguice:1.1.2')
    testCompile('junit:junit:4.8.2')
    testCompile project (':app')
    testCompile files(androidJar)
}

sourceSets.test.compileClasspath = configurations.robo + sourceSets.test.compileClasspath
sourceSets.test.runtimeClasspath = configurations.robo + sourceSets.test.runtimeClasspath

test {
    excludes = ['**/MyRobolectricTestRunner.class']
}

我不得不为测试运行器添加一个排除项,否则Gradle将抛出异常。

MyRobolectricTestRunner.java 看起来像这样:

package com.acme.myapp;

import java.io.File;
import org.junit.runners.model.InitializationError;
import roboguice.application.RoboApplication;
import roboguice.inject.ContextScope;
import com.google.inject.Injector;
import com.xtremelabs.robolectric.Robolectric;
import com.xtremelabs.robolectric.RobolectricTestRunner;

public class MyRobolectricTestRunner extends RobolectricTestRunner {
    public MyRobolectricTestRunner(Class<?> testClass) throws InitializationError {
        // Tell Robolectric where to find AndroidManifest.xml and res/
        super(testClass, new File("../app"));
    }

    /**
     * Enable injection into tests as well...
     */
    @Override
    public void prepareTest(Object test) {
        RoboApplication myApplication = (RoboApplication) Robolectric.application;
        Injector injector = myApplication.getInjector();
        ContextScope contextScope = injector.getInstance(ContextScope.class);
        contextScope.enter(myApplication);
        injector.injectMembers(test);
    }

}

这是一个示例测试,说明注入:

package com.acme.myapp;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import roboguice.inject.InjectResource;

@RunWith(MyRobolectricTestRunner.class)
public class StringFormattingTest {

    @InjectResource(R.string.info_pending_amount)
    private String pendingAmountPattern;

    @Test
    public void testFormatInfoPendingAmount() {
        String s = String.format(pendingAmountPattern, 20.0d, "EUR");
        assertEquals("Only a part of your stake (20,00 EUR) was accepted", s);
    }

}

10
2017-09-02 08:51



你如何参考你的:app?通过自己的settings.gradle? :app还会为要使用的测试公开自己的依赖项吗? - Moritz
我们可以在github上获得一个简单的样本吗? - Gary


这可能有效:

configurations { robo }

dependencies {
  robo ...
  testRuntime ...
}

sourceSets.test.runtimeClasspath = configurations.robo + sourceSets.test.runtimeClasspath

4
2017-08-31 07:40



我还必须将r​​obo添加到compileClasspath - Olle Hallin
@Peter你知道怎么做 在这种情况下更改类路径的顺序 ... - JJD