如何覆盖Robolectric运行时依赖性存储库URL?

时间:2016-09-06 22:27:49

标签: android android-gradle robolectric

我们正在尝试使用内部Nexus存储库中的org.robolectric:robolectric:3.0依赖项。问题是Robolectric尝试从公共存储库(as mentioned here)在运行时加载一些依赖项,并忽略build.gradle中的任何存储库覆盖。

由于我们无法从内部网访问该公共位置,因此在尝试加载该依赖项后,我的测试会超时:

  

[警告]无法获取资源   'org.robolectric:android-all:jar:5.0.0_r2-robolectric-1'来自   存储库sonatype(https://oss.sonatype.org/content/groups/public/):   传输文件时出错:操作超时

Robolectric configuration documentation的底部会建议将其添加到您的Gradle配置中以覆盖网址:

android {
  testOptions {
    unitTests.all {
      systemProperty 'robolectric.dependency.repo.url', 'https://local-mirror/repo'
      systemProperty 'robolectric.dependency.repo.id', 'local'
    }
  }
}

不幸的是,我已经测试过了,我从未看到系统属性被设置。我从我的自定义Robolectric运行器(扩展RobolectricGradleTestRunner)内部打印出来,并且系统属性保持设置为空。

System.out.println("robolectric.dependency.repo.url: " + System.getProperty("robolectric.dependency.repo.url"));

我还尝试做类似于this comment的事情(但是这个方法不存在以在RobolectricGradleTestRunner中覆盖),我也尝试直接在我的自定义Robolectric运行器中设置系统属性,并且这似乎没有帮助。

@Config(constants = BuildConfig.class)
public class CustomRobolectricRunner extends RobolectricGradleTestRunner {
    private static final String BUILD_OUTPUT = "build/intermediates";

    public CustomRobolectricRunner(Class<?> testClass) throws InitializationError {
        super(testClass);

        System.setProperty("robolectric.dependency.repo.url", "https://nexus.myinternaldomain.com/content");
        System.setProperty("robolectric.dependency.repo.id", "internal");

        System.out.println("robolectric.dependency.repo.url: " + System.getProperty("robolectric.dependency.repo.url"));
    }

Robolectric source code似乎确实存在这些系统属性。

4 个答案:

答案 0 :(得分:7)

虽然不是直接使用属性的修复方法,但另一种方法是通过覆盖getJarResolver()子类中的RobolectricTestRunner并将其指向工件主机:

public final class MyTestRunner extends RobolectricTestRunner {
  public MyTestRunner(Class<?> testClass) throws InitializationError {
    super(testClass);
  }

  @Override protected DependencyResolver getJarResolver() {
    return new CustomDependencyResolver();
  }

  static final class CustomDependencyResolver implements DependencyResolver {
    private final Project project = new Project();

    @Override public URL[] getLocalArtifactUrls(DependencyJar... dependencies) {
      DependenciesTask dependenciesTask = new DependenciesTask();
      RemoteRepository repository = new RemoteRepository();
      repository.setUrl("https://my-nexus.example.com/content/groups/public");
      repository.setId("my-nexus");
      dependenciesTask.addConfiguredRemoteRepository(repository);
      dependenciesTask.setProject(project);
      for (DependencyJar dependencyJar : dependencies) {
        Dependency dependency = new Dependency();
        dependency.setArtifactId(dependencyJar.getArtifactId());
        dependency.setGroupId(dependencyJar.getGroupId());
        dependency.setType(dependencyJar.getType());
        dependency.setVersion(dependencyJar.getVersion());
        if (dependencyJar.getClassifier() != null) {
          dependency.setClassifier(dependencyJar.getClassifier());
        }
        dependenciesTask.addDependency(dependency);
      }
      dependenciesTask.execute();

      @SuppressWarnings("unchecked")
      Hashtable<String, String> artifacts = project.getProperties();
      URL[] urls = new URL[dependencies.length];
      for (int i = 0; i < urls.length; i++) {
        try {
          urls[i] = Util.url(artifacts.get(key(dependencies[i])));
        } catch (MalformedURLException e) {
          throw new RuntimeException(e);
        }
      }
      return urls;
    }

    @Override public URL getLocalArtifactUrl(DependencyJar dependency) {
      URL[] urls = getLocalArtifactUrls(dependency);
      if (urls.length > 0) {
        return urls[0];
      }
      return null;
    }

    private String key(DependencyJar dependency) {
      String key =
          dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getType();
      if (dependency.getClassifier() != null) {
        key += ":" + dependency.getClassifier();
      }
      return key;
    }
  }
}

应该注意的是,这依赖于两个内部类型的Robolectric,因此在升级版本时应该小心。

答案 1 :(得分:5)

您可以设置MavenDependencyResolver使用的const addmm = x => y => array.map(maybe.of)(addm(x)(y)) arraym.chain(x => arraym.chain( addmm(x) )(arrayOfMaybes))([[10]]) mavenRepositoryIdmavenRepositoryUrl的属性。

示例:

RoboSettings

答案 2 :(得分:1)

根据linked Github issue,一个解决方法是在settings.xml文件夹中配置~\.m2

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <mirrors>
        <mirror>
            <id>jcenter</id>
            <name>JCenter Remote</name>
            <mirrorOf>*</mirrorOf>
            <url>https://www.example.com/artifactory/jcenter-remote/</url>
        </mirror>
    </mirrors>
</settings>

<mirrorOf>*</mirrorOf>似乎有必要强制Maven将所有存储库请求重定向到一个远程数据库。有关Maven中镜像设置的更多详细信息,请参阅here

我发现使用远程的Sonatype是不够的,你应该使用远程的JCenter或Maven Central来获得所有的传递依赖。

答案 3 :(得分:-1)

在撰写本文时,以前的答案现在已过时。如果您引用的是最新的robolectric documentation,则需要像这样覆盖robolectric.dependency.repo.url属性:

android {
  testOptions {
    unitTests.all {
      systemProperty 'robolectric.dependency.repo.url', 'https://local-mirror/repo'
      systemProperty 'robolectric.dependency.repo.id', 'local'
    }
  }
}