一、单元测试
单元测试一直是编程开发重要的一部分,但在 Android 应用开发经常被忽视,转而由人工测试替代。除了 Android 功能测试涉及代码编写外,还有上下依赖的 context 传递,但这一切都不该是我们直接放弃单元测试的原因,单元测试除了在代码编写后检查设计功能的完整性,还能快速捕获和修复因代码更改(重构、优化等)带来的回归问题。
今天主要介绍 Robolectric 的环境搭载,如果对于单元测试有兴趣的话,可以点击阅读链接了解 单元测试
二、Robolectric
Pivotal实验室推出的Robolectric,通过使用Robolectrict模拟Android系统核心库的Shadow Classes的方式,我们可以像写本地测试一样写这类测试,并且直接运行在工作环境的JVM上
简单说,它能够模拟出 Android 系统,直接在jvm测试你的代码,而不用把你的代码编译在你的开发设备上运行。
为什么要使用它,它解决的是什么问题?
众所周知 Android 存在上下文依赖,如果用其他测试框架(如junit),大部分测试功能逻辑没有问题,一旦涉及到 context 的功能基本歇菜,比如我们测试 SharedPreferecnce,测试数据库(创建需要context)等等,所以引入这个框架可以让我们轻松模拟出 context 进行测试。当然,你的 activity 页面同样能进行测试。
如何使用
在 maven 中央仓库 搜索 robolectric,选择版本,在module build.gradle 添加依赖 testImplementation 'org.robolectric:robolectric:4.2.1'
再添加测试配置
android {
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
复制代码
点击同步,接下来就是编写测试用例,我们随便写一个。
ok,点击运行,我们可以在 run 中看到运行的日志,如下:
如果你的网络没问题,在等待下载成功后,你可以在 C:\Users\Administrator.m2\repository\org\robolectric\android-all 看到完整依赖库文件。那么你也可以停步在这,关闭这篇文章,因为本文讲的是远程下载失败,如何快速修复下载这个问题。
从日志截图我们可以看到,下载地址是 https://oss.sonatype.org/content/groups/public/
,提示连接超时。开始我们的补救措施
解决思路
-
确定需下载的版本,其实在写完测试用例后,运行,就能在 run 日志中看到版本号,我这边显示的版本是 4.1.2
-
确定要下载的文件
- 版本xx.jar
- 版本xx.jar.sha1
- 版本xx.pom
- 版本xx.pom.sha1
-
去哪里下载
-
在本文最下面会说明如何修改下载地址,使其指向阿里云仓库下载,但我测试不可用,同样是下载不完全的问题。通过先官网(oss.sonatype.org/content/gro…) 访问速度太差,即使架了梯子也无济于事,所以从阿里下载,但不是修改指向 url 方式,而是通过添加依赖的方式把 jar 包从仓库拉取下来,如图
-
添加依赖:
implementation 'org.robolectric:android-all:4.1.2_r1-robolectric-r1'
,选择版本要和日志显示的版本一致,同步 -
在.gradle 中找jar包,复制到 .m2 对应路径中,最终如下 找到文件,右键浏览器中显示
复制到 C:\Users\Administrator.m2\repository\org\robolectric\android-all\4.1.2_r1-robolectric-r1,如图
-
运行,因为还需要另外三个文件,但文件较小,可以尝试远程拉取,但下载失败的话,可以从官网直接下载,就1、2Kb,很快,注意版本号要一致,复制到 .m2 同一文件夹中。官网地址 https://oss.sonatype.org/content/groups/public/org/robolectric/android-all/ 访问特别慢,要有耐心
-
重新运行测试用例,通过!
-
三、总结
- robolectric 仓库可以拉取的话,优先使用,因为省事
- 官网无法下载,那么只要我们能把文件找齐放进指定目录同样能解决问题
- 阿里仓库(或者其他镜像仓库)访问速度一流,项目依赖后会下载到
C:\Users\Administrator\.gradle\caches\modules-2\files-2.1\org.robolectric\android-all\xxx
中,拷贝出来就是 - 确保下载版本一致。我测试项目下载的是 4.1.2 版本,另一个项目下载的是 8.1.0,所以版本要细看日志。
直接修改远程下载地址
这里是另外一种思路,但我测试并不能用,虽然能下载,但 xx.jar 下载到本地只有几十kb
在日志中发现,依赖是从官网 oss.sonatype.org 下载,所以我们修改 url 指向就行
依赖库是哪里下载的?
一般我们项目都会指定一个镜像仓库,如阿里远程仓库,我们也检查过阿里仓库包含这个依赖,但是仅仅在 gradle 配置是不够的,robolectric 的下载还是通过他们的官网,所以要修改配置的url
-
怎么修改,先问这个配置从哪里来? 查看类 MavenRoboSettings,发现配置下载地址和id,4.2.1版本改成从 System Property 读取,我们修改这个配置就行,原代码如下:
@Deprecated public class MavenRoboSettings { private static String mavenRepositoryId; private static String mavenRepositoryUrl; private static String mavenRepositoryUserName; private static String mavenRepositoryPassword; static { mavenRepositoryId = System.getProperty("robolectric.dependency.repo.id", "sonatype"); mavenRepositoryUrl = System.getProperty("robolectric.dependency.repo.url", "https://oss.sonatype.org/content/groups/public/"); mavenRepositoryUserName = System.getProperty("robolectric.dependency.repo.username"); mavenRepositoryPassword = System.getProperty("robolectric.dependency.repo.password"); } //...省略 复制代码
-
修改下载路径 继承 RobolectricTestRunner,直接配置地址,代码如下
public class MRobolectricTestRunner extends RobolectricTestRunner { static { System.setProperty("robolectric.dependency.repo.id", "alimaven"); System.setProperty("robolectric.dependency.repo.url", "http://maven.aliyun.com/nexus/content/groups/public/"); //或者 //MavenRoboSettings.setMavenRepositoryId("alimaven"); //MavenRoboSettings.setMavenRepositoryUrl("http://maven.aliyun.com/nexus/content/groups/public/"); } public MRobolectricTestRunner(Class<?> testClass) throws InitializationError { super(testClass); } } 复制代码
删除 C:\Users\Administrator.m2\repository\org\robolectric\android-all\8.0.0_r4-robolectric-r11 文件夹,不然还是会从官网下载,给测试用例添加配置,运行
测试用例代码,需把配置修改为我们自定义的 MRobolectricTestRunner,App.class 只是一个继承Application的空类,与测试用例同级目录 :
日志截图,已经从我们指定的仓库下载了
不过遗憾的是提示失败了,** CHECKSUM FAILED - Checksum failed on download: local = '3c358703a42a9475fed4a63bee9c744932ad9ff7'; remote = '<!DOCTYPE' - RETRYING** 如果有知道如何处理这个情况的,欢迎提供思路,抱拳
-
在官网提供了另外一种配置
android { testOptions { unitTests.all { systemProperty 'robolectric.dependency.repo.url', 'https://local-mirror/repo' systemProperty 'robolectric.dependency.repo.id', 'local' } } } 复制代码
不过测试发现只有在命令行中调用测试才会读取这个配置,命令:gradlew test
参考文章: