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包:

添加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”即可;运行结果如下:

运行结果

若断言失败,测试用例通不过:

断言失败

点击箭头部分可导出测试结果,并可自定义路径和格式:

文件路径

生成的结果如图:

测试结果

可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文件中添加 app/src/test即可[具体API使用见官网  http://robolectric.org/javadoc/3.0/index.html]

博客地址:Android单元测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值