Android 单元测试,在 Android 开发过程中,一般模式大抵为编写好程序,然后运行在 Android 虚拟机或真机上(考虑到电脑配置太低,虚拟机太慢等情况,用虚拟机运行程序很少见);若要调试程序,一般采用打 Log 日志、打断点 Debug 等方式,定位到某处可能存在 bug,再修改代码,反复运行。而每加载一次 app 都需要编译整个项目,速度很慢;有时可能仅仅是修改了某个页面的很小的判断就需要重新编译一次,在真机上一路点击到刚修改的页面,然后模拟可能出现 bug 的情形,甚至不异让测试用手指不断狂点屏幕。若能像开发 Javeweb 那样,直接在编写代码时直接运行一次写好的测试用例,就知道自己刚编写的代码是否正确,或直接在控制台输出想要的结果而不需加载完整个项目,岂不方便了许多。
AndroidApp 运行在 delvik 上面,而开发是在 JVM 上,在开发一个项目的时候,需要指定一个 API-level, 其实就是将下载的 SDK 里对应的 android.jar 回到这个项目的 build.path 里去,然后再编译打包。但 IDE 和 SDK 只提供了开发和编译项目的环境,而没有提供运行项目的环境,在 SDK 的 android.jar 里的 class 只是一些 stub, 所有方法只有一行实现:
throw RuntimeException("stub!!")
若只运行 unit test,就会抛出该异常。故要能在 JVM 中就进行单元测试,这里引用一个开源的 framework,即 robolectric(官网:http://robolectric.org/);它通过实现一套 JVM 能运行的 Android 代码,然后在 unit test 运行的时候去截取 android 相关的代码调用,然后转到他们的他们实现的代码去执行这个调用的过程。该文即主要介绍 robolectric 的使用。
一、robolectric 环境搭建
环境配置:Windows 7+AndroidStudio 1.3
1. 在项目的的 build.gradle 中加入要引入的包:
- testCompile "org.robolectric:robolectric:3.0"
(注:gradle 1.0.0 的版本在编译时会提示找不到 testCompile 方法,需要 1.1 版本以上;根据提示直接将 gradle 版本更新到相应版本即可,我更新的版本为 1.2.3;在 androidStudio1.1 版本前需要添加 testCompile "junit:junit:4.10")
详见 AndroidStudio 版本更新说明:http://tools.android.com/tech-docs/new-build-system
2. 将 Build Variant 里面的 Test Artifact 选择为 Unit Tests;
[若没有 Test Artifact,不可选择,则需要 AndroidStudio 升级到 1.1 版本以上,详见版本更新说明 http://tools.android.com/tech-docs/new-build-system]
二、创建单元测试
在 AndroidStuio1.1 版本后每新创建一个项目,会自动生成一个 test 包,位于 app/src/androidTest 下,但若使用 robolectric,最好将 androidTest 重命名为 test; 如图:
详见 AndroidStudio 版本更新说明:http://tools.android.com/tech-docs/new-build-system 若是项目中没有 test 文件夹,须手动添加:a. 先创建一个 test 目录,再在目录下添加 java 包:
b. 创建与项目相同的包名,如上图。
c. 在 gradle 中指定其为测试目录:
- sourceSets {
- androidTest.setRoot('src/test')
- }
三、运行测试
1. 在要创建单元测试的类名上使用快捷提示 (AndroidStudio 原生快捷键 alt+Enter),点击 "Create Test", 在弹出的对话框中选择要测试的方法:
androidStudio 会自动在 test 对应的目录下创建测试类;由于测试类及方法是运行在 JVM 中的,日志也会在控制台中输出,故要打印日志用 System.out.print() 而非 Log;所有的测试方法须以 test 开头;
加入注解和要测试的 API-level,v 如:
- @RunWith(RobolectricTestRunner.class)@Config(constants = BuildConfig.class, sdk = 21) public class UtilityTest extends TestCase {@Test public void testGetScreenWidth() throws Exception {
- System.out.print("屏幕宽:\n" + Utility.getScreenWidth(RuntimeEnvironment.application) + "\n");
- assertEquals(Utility.getScreenWidth(RuntimeEnvironment.application), 480);
- }
- }
在类名上点击右键,选择 "Run xxxTest" 即可;运行结果如下:
若断言失败,测试用例通不过:
点击箭头部分可导出测试结果,并可自定义路径和格式:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="文件路径" src="/uploadfile/Collfiles/20170301/20170301100132777.png" title="\" />
生成的结果如图:
可 config 的注解中直接指定 AndroidManifest.xml, 如:
- @Config(manifest="./src/main/AndroidManifest.xml")
但一般是自定义一个类,指定 AndroidManifest.xml;
- public class CustomTestRunner extends RobolectricTestRunner {
- public CustomTestRunner(Class testClass) throws InitializationError {
- super(testClass);
- }@Override protected AndroidManifest getAppManifest(Config config) {
- final String type = BuildConfig.BUILD_TYPE;
- final String flavor = BuildConfig.FLAVOR;
- final String packageName = BuildConfig.APPLICATION_ID;
- final FileFsFile res;
- final FileFsFile assets;
- final FileFsFile manifest;
- if (FileFsFile.from(BUILD_OUTPUT, "res", "merged").exists()) {
- res = FileFsFile.from(BUILD_OUTPUT, "res", "merged", flavor, type);
- } else if (FileFsFile.from(BUILD_OUTPUT, "res").exists()) {
- res = FileFsFile.from(BUILD_OUTPUT, "res", flavor, type);
- } else {
- res = FileFsFile.from(BUILD_OUTPUT, "bundles", flavor, type, "res");
- }
- if (FileFsFile.from(BUILD_OUTPUT, "assets").exists()) {
- assets = FileFsFile.from(BUILD_OUTPUT, "assets", flavor, type);
- } else {
- assets = FileFsFile.from(BUILD_OUTPUT, "bundles", flavor, type, "assets");
- }
- if (FileFsFile.from(BUILD_OUTPUT, "manifests").exists()) {
- manifest = FileFsFile.from(BUILD_OUTPUT, "manifests", "full", flavor, type, "AndroidManifest.xml");
- } else {
- manifest = FileFsFile.from(BUILD_OUTPUT, "bundles", flavor, type, "AndroidManifest.xml");}return new AndroidManifest(manifest, res, assets, packageName); }}"
然后在 RunWith 指定该 Runner:
- @RunWith(CustomTestRunner.class)@Config(constants = BuildConfig.class, sdk = 21) public class UtilityTest extendsTestCase {...
- }
若要将 test 目录下的测试用例只保留在本地,则在. gitignore 文件中添加。
就爱阅读 www.92to.com 网友整理上传, 为您提供最全的知识大全, 期待您的分享,转载请注明出处。
来源: http://www.92to.com/bangong/2017/03-01/17904777.html