如何覆盖 Robolectric 运行时依赖库 URL?
How to override the Robolectric runtime dependency repository URL?
我们正在尝试使用我们自己的内部 Nexus 存储库中的 org.robolectric:robolectric:3.0
依赖项。问题是 Robolectric 尝试在运行时从 public 存储库 (as mentioned here) 加载一些依赖项,并忽略 build.gradle.
中的任何存储库覆盖
由于我们无法从我们的内部网访问那个 public 位置,我的测试在尝试加载该依赖项后超时:
[WARNING] Unable to get resource
'org.robolectric:android-all:jar:5.0.0_r2-robolectric-1' from
repository sonatype (https://oss.sonatype.org/content/groups/public/):
Error transferring file: Operation timed out
Robolectric configuration documentation 的底部建议将此添加到您的 Gradle 配置以覆盖 URL:
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 似乎确实证实了这些系统属性的存在。
虽然不能直接使用这些属性,但另一种方法是在 RobolectricTestRunner
子类中重写 getJarResolver()
并将其指向您的工件主机:
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的两个内部类,所以升级版本时要小心。
您可以设置 RoboSettings
的 mavenRepositoryId
和 mavenRepositoryUrl
属性,它们由 MavenDependencyResolver
使用。
示例:
public class CustomRobolectricRunner extends RobolectricGradleTestRunner {
static {
RoboSettings.setMavenRepositoryId("my-nexus");
RoboSettings.setMavenRepositoryUrl("https://my-nexus.example.com/content/groups/public");
}
...
}
根据 linked Github issue,一种解决方法是在 ~\.m2
文件夹中配置 settings.xml
:
<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 的远程来获取所有的传递依赖。
截至撰写本文时,那些以前的答案现已过时。如果您参考最新的 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'
}
}
}
我们正在尝试使用我们自己的内部 Nexus 存储库中的 org.robolectric:robolectric:3.0
依赖项。问题是 Robolectric 尝试在运行时从 public 存储库 (as mentioned here) 加载一些依赖项,并忽略 build.gradle.
由于我们无法从我们的内部网访问那个 public 位置,我的测试在尝试加载该依赖项后超时:
[WARNING] Unable to get resource 'org.robolectric:android-all:jar:5.0.0_r2-robolectric-1' from repository sonatype (https://oss.sonatype.org/content/groups/public/): Error transferring file: Operation timed out
Robolectric configuration documentation 的底部建议将此添加到您的 Gradle 配置以覆盖 URL:
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 似乎确实证实了这些系统属性的存在。
虽然不能直接使用这些属性,但另一种方法是在 RobolectricTestRunner
子类中重写 getJarResolver()
并将其指向您的工件主机:
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的两个内部类,所以升级版本时要小心。
您可以设置 RoboSettings
的 mavenRepositoryId
和 mavenRepositoryUrl
属性,它们由 MavenDependencyResolver
使用。
示例:
public class CustomRobolectricRunner extends RobolectricGradleTestRunner {
static {
RoboSettings.setMavenRepositoryId("my-nexus");
RoboSettings.setMavenRepositoryUrl("https://my-nexus.example.com/content/groups/public");
}
...
}
根据 linked Github issue,一种解决方法是在 ~\.m2
文件夹中配置 settings.xml
:
<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 的远程来获取所有的传递依赖。
截至撰写本文时,那些以前的答案现已过时。如果您参考最新的 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'
}
}
}