Android单元测试基本知识

单元测试简介

在Android Studio上进行单元测试是相对来说比较简单的,主要可以分为两类:

  • local unit test : 本地单元测试
    本地单元测试是跑在本地JVM上的,不依赖于Android设备,所以无法测试依赖于Andorid框架的代码。优点是运行速度快,可以直接访问你电脑上的本地资源。

在运行local unit test时,android.jar将不包含任何实际的代码,如果在运行local unit test时调用了android框架代码,那么将会报

Error: "Method... not mocked"

解决方案有两种:

  • 利用instrumentation test来进行测试

  • 在project build.gradle文件中添加

android {...testOptions {unitTests.returnDefaultValues = true}
}

这样所有的android框架代码的方法均会返回默认值0或者null。当然这并不是一种值得推荐的方法。

Android Studio默认使用JUnit来进行单元测试,但是你也可以Mockito等测试框架来拓展测试能力。

  • instrumentation test : 仪器单元测试
    仪器单元测试是跑在Android设备上的,可以用于测试依赖于Android框架的代码。Android Studio默认采用Espresso来进行测试。

instrumentation test实际上运行了两个app。第一个是被测试的app,第二个是instrumentation test所在的application,androidTest目录下其实包含了一个完整的工程,如manifest文件、资源文件等,只不过这些文件已经完全被隐藏。系统在同一个进程下运行这两个app,因此测试app可以调用app的方法和修改app的变量。

一般来说,这两种单元测试各有其优缺点,我一般用instrumentation test比较多。

编写单元测试

Android Studio默认已经给我们添加好了单元测试需要的依赖框架,我们只需要在相应的类或方法上,点击Ctrl+Shift+T生成相应的测试类,然后编写相应的测试代码即可。

for example:
新建一个Calculator类

public class Calculator {public int add(int a, int b) {return a = b;}
}

在Calculator类上点击ctrl+shift+T,直接在androidTest/java/目录下生成CalculatorTest.java文件。然后在CalculatorTest.java右键可以直接运行该单元测试文件。

public class CalculatorTest {@Testpublic void add() throws Exception {Calculator calculator = new Calculator();assertEquals(2, calculator.add(1, 1));}}

为什么这里选择androidTest/java而不是test/java目录,因为前者是真正的Android设备环境,使用起来也很方便,并且后续生成测试代码覆盖率报告时也会很方便。

单元测试mock

有时我们想单独对某个模块进行测试,但是这个模块依赖于其他未完成的模块,这时我们可以使用单元测试的mock功能,单元测试的mock也分为两种:

local unit test的mock

常用的local unit test单元测试框架为mockito,使用方法分为如下几个步骤:
1、在module的build.gradle文件中添加mockito依赖

testCompile 'org.mockito:mockito-core:1.10.19'  // 注意这里testCompile和androidTestCompile的区别,testCompile是对local unit test的,而androidTestCompile针对于instrumentation test

2、在测试的定义处添加注解

@RunWith(MockitoJUnitRunner.class)

3、创建mock对象,并在定义处添加@Mock注解
4、构建when()… then()… 语句定义mock的方法和返回值。

@RunWith(MockitoJUnitRunner.class)
public class CalculatorTest {@MockCalculator calculator;@Testpublic void add() throws Exception {when(calculator.add(3,2)).thenReturn(4);assertEquals(4, calculator.add(1, 2));}}

这里有几个值得注意的事:

  • testCompile ‘org.mockito:mockito-core:1.10.19’,不要写为androidTestCompile ‘org.mockito:mockito-core:1.10.19’,否则会找不到mockito依赖。

  • 如果when…then… 语句中定义的参数和实际调用的不一致,那么如果返回值是基本类型,则返回空,否则返回null。

网络服务的单元测试

一般对于网络服务单元测试有两种选择,一种是对网络服务进行mock,另一种是直接访问网络。这里我更倾向于第二种方式,因为首先mock那么多的网络接口也是一种麻烦事,其次mock的接口的返回情况可能和实际值也会存在一定的偏差。

网络服务一般也可以分为两种,第一种为同步服务,另一种为异步服务。同步服务直接调用接口获取返回值并对返回值进行判断即可。而异步稍微有点麻烦。

要想对异步服务进行测试,我们首先要清楚Android Studio对单元测试代码运行的基本原理。Android Studio采用了一个单线程,(除了@Before和@After),不断调用@Test方法(不保证调用的顺序),一定要注意的是assert方法必须要在该线程中执行才会有效。知道了这点,异步服务的单测也就明朗了。
我们在发送请求后,将单元测试线程阻塞住,等到获取服务器返回的结果后,再释放单元测试线程,并在单元测试线程中执行assert语句即可。

同步网络服务单元测试

@Test
public void createDir() throws Exception {CreateDirRequest createDirRequest = new CreateDirRequest();CreateDirResult createDirResult = client.createDir(createDirRequest); // 同步网络服务接口assertEquals(true, isSuccess(createDirResult)); // 判断网络任务是否正确执行
}

异步网络服务单元测试

    @Testpublic void createDirAsyn() throws Exception {final CountDownLatch countDownLatch = new CountDownLatch(1);CreateDirRequest createDirRequest = new CreateDirRequest();unitTestResult = false; // 用于记录执行结果createDirRequest.setListener(new ICmdTaskListener() {@Overridepublic void onSuccess(COSRequest cosRequest, COSResult cosResult) {unitTestResult = isSuccess(cosResult);countDownLatch.countDown();}@Overridepublic void onFailed(COSRequest cosRequest, COSResult cosResult) {unitTestResult = isSuccess(cosResult) countDownLatch.countDown();}});client.createDir(createDirRequest); // 执行异步任务countDownLatch.await(); // 等待任务执行结束assertEquals(true, unitTestResult); // 判断执行结果}

单元测试相关命令

1、运行local unit test

gradlew testDebugUnitTest

2、运行instrumentation test并生成测试报告

gradlew createDebugCoverageReport

注意想要生成代码覆盖率报告,需要在module的build.gradle文件下添加

buildTypes {debug {testCoverageEnabled true}
}

单元测试常见问题:

如何获取Context

1、Context context = new MockContext();
2、Context context = InstrumentationRegistry.getContext(); // 获取测试app的context
3、Context context = InstrumentationRegistry.getTargetContext(); // 获取被测试app的context

第一种方式获取的context在调用getSystemService()方法时或报错,而后两种不会。

日志输出

我在Android Studio 2.3版本上运行instrumentation test,并在Android Monitor中不选择任何过滤器,是可以查看日志的。但是同事在Android Studio 2.1版本上却无法打印日志。

文件读取Permission Denied

场景:自己在Android项目下新建了一个module,其中有个方法调用了写文件代码,然后在进行单元测试时总是报:

java.io.FileNotFoundException: /storage/emulated/0/test.txt: open failed: EACCES (Permission denied)

原因:需要在该module上添加权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

其次由于Android6.0的动态权限特性,如果是targetSdkVersion >= 23,且运行单元测试的手机系统大于或者等于Android6.0,需要降低targetSdkVersion或者使用低于Android6.0的手机。

Test run failed: Instrumentation run failed due to ‘Process crashed.’

是否添加了如下依赖:

androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {exclude group: 'com.android.support', module: 'support-annotations'})

junit.framework.AssertionFailedError: No tests found in com.tencent.cos.COSClientTest

是否配置了

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

no test were found

这个错误导致的原因有很多,基本上都是使用或者配置上的错误。

org.mockito.exceptions.misusing.MissingMethodInvocationException:

public class CalculatorTest {@MockCalculator calculator;@Testpublic void add() throws Exception {//calculator = new Calculator();    // 这里不能再初始化when(calculator.add(1,2)).thenReturn(4);calculator = new Calculator();assertEquals(4, calculator.add(1, 2));}
}

.Instrumentation run failed due to ‘java.lang.NoClassDefFoundError

在单独运行每个测试类时运行正常,但是调用./gradlew connectedAndroidTest命令来运行单元测试就会报如上错误。更奇葩的是自己在api level为16的模拟器上没有这个问题,在api level为23的真机上就会出现这个问题。

这里值得注意的是instrumentation test并不强制需要application module,只包含library module完全可以进行单元测试

检查了一下午,才发现fastjson和testInstrumentationRunner “android.support.test.runner.AndroidJUnitRunner”有冲突,奇葩的是在1.2.35以及之前的版本存在这个问题,1.2.36和1.2.37就会有这个问题。

Android单元测试那些事儿(一)相关推荐

  1. Android单元测试全解

      自动化测试麻烦吗?说实在,麻烦!有一定的学习成本.但是,自动化测试有以下优点: 节省时间:可以指定测试某一个activity,不需要一个个自己点 单元测试:既然Java可以进行单元测试,Andro ...

  2. Android 单元测试学习计划

    网上查了一下Android单元测试相关的知识点,总结了一个学习步骤: 1. 什么是单元测试 2. 单元测试正反面: 2.1. 重要性 2.2. 缺陷 2.3. 策略 3. 单元测试的基础知识: 3.1 ...

  3. Android单元测试 - 几个重要问题

    前言 已经一个月没写文章了,由于9月份在plan国庆旅行计划,国庆前前后后去了14天旅行,所以没时间写,哈哈. 言归正传,上一篇文章<Android单元测试 - 如何开始?>介绍了几款单元 ...

  4. Android单元测试框架Robolectric3.0介绍(二)

    文章中的所有代码在此:https://github.com/geniusmart/LoveUT ,由于 Robolectric 3.0 和 3.1 版本(包括后续3.x版本)差异不小,该工程中包含这两 ...

  5. Android单元测试研究与实践

    处于高速迭代开发中的Android项目往往需要除黑盒测试外更加可靠的质量保障,这正是单元测试的用武之地.单元测试周期性对项目进行函数级别的测试,在良好的覆盖率下,能够持续维护代码逻辑,从而支持项目从容 ...

  6. Android单元测试 - Sqlite、SharedPreference、Assets、文件操作 怎么测?

    前言 上篇<Android单元测试 - 几个重要问题> 讲解了"何解决Android依赖.隔离Native方法.静态方法.RxJava异步转同步"这几个Presente ...

  7. android单元测试作用,Android单元测试源码解读

    Android手机操作系统是一个开源的操作系统.程序员们可以在模拟器的帮助下对其进行修改,来实现各种功能需求,满足用户的应用.在这里我们先来了解一下Android单元测试的相关内容. 在网络上找了半天 ...

  8. android开发那些事儿(五)-通用流行框架大全

    1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Android Universal Image Loader 一个强大的加载,缓存,展示图 ...

  9. android单元测试android环境,基于Robolectric的Android单元测试 —环境搭建与部署运行...

    移动端的测试中,因为回归一些逻辑分支比较多的功能时工作量比较大,且不太适合用UI完成,尝试通过单元测试来完成.几经波折终于完成了一个功能的UT用例并在CI上部署运行,现总结如下: 一.Robolect ...

最新文章

  1. Set Up a Mobile Worker
  2. Array K-Coloring
  3. iOS中的WiFi与硬件通信
  4. leetcode 706. 设计哈希映射
  5. 局域网网络风暴检测工具_【思唯网络学院】从原理到配置,最全的VLAN说明就在这了!...
  6. Context 之我见
  7. Java深入 - servlet和Spring的DispatcherServlet详解
  8. Spring Boot学习总结(15)——Spring Boot优缺点再总结
  9. amd cpu不能在cmd环境下运行java代码_Golang安装与环境搭建并在VSCode里面输出HelloWord...
  10. java 读取clob字段的几种方法
  11. Spring MVC 切面 ResponseBodyAdvice 对返回值增强
  12. jq实现点击复制文本功能
  13. 哨兵-2 Sentinel-2 数据下载(USGS)
  14. c语言数字转化为英文版,(C语言编写的英语数字转化代码数字转化为用英语表达的数字.doc...
  15. 触动的话语,为自己而活
  16. Android开发实用小技巧九——内嵌WebView的使用(内置浏览器)
  17. 【编译原理】自上而下分析与LL文法
  18. 关于CList的小知识
  19. 深入理解synchronized
  20. ubuntu安装 veloview_Pointnet+Frustum-Pointnet复现(Pytorch1.3+Ubuntu18.04)

热门文章

  1. 精通python如何赚钱_用Python在休闲期月入5000千+!掌握生产工具,就能赚钱
  2. java 单独用this_以下不是Java中this关键字的作用的是()。
  3. 通俗易懂彻底理解十倍交叉验证法
  4. 老王固的艰巨且持久的学习计划
  5. Vscode连接远程服务器(一套配置成功)
  6. 计算机视觉3.1:数据增强
  7. 【QQ红包】手机发抢不到的口令红包
  8. 蓝牙技术|AirPods Pro 2或将搭载运动传感器,TWS蓝牙耳机发展新方向
  9. ORB-SLAM3 细读单目初始化过程(下)
  10. 计算机等级考试建议报考,全国计算机二级考试:科目报考建议