Android代码单元测试

Android代码单元测试

1. 目的

  • 单元测试是白盒测试,可以验证具体的功能模块逻辑是否正确
  • 保证代码质量,对代码逻辑进行方法级别的测试,确保每一个功能模块的逻辑正确
  • 在良好的单测覆盖率之下,项目可以在保证质量的前提下进行快速迭代

2. 测试用例覆盖范围

一个待测试页面对应多个业务单元,每一个业务单元对应一个测试用例,每一个测试用例都是一条链路(好比点击一个按钮后产生的一系列直接影响如页面跳转等),实现条件覆盖和路径覆盖。
在Android单元测试中,测试用例不须要覆盖全部的方法逻辑(这也是不太现实的),应该专一于本身编写的业务逻辑等代码的测试覆盖,像 Android SDK 里的方法回调是不须要测试的。html

3. 怎样测试逻辑方法

3.1 目标方法有明确的返回值

编写单元测试时调用这个方法,验证返回值是否符合预期android

3.2 目标方法自己没有返回值,可是会改变一些对象的(属性||状态)

调用该方法,而后验证方法改变的对象的(属性||状态)是否符合预期git

3.3 目标方法没有返回值,也不会改变对象

调用该方法,而后验证其行为,好比按钮的点击事件,验证是否弹出Toast、是否有弹框、是否有页面跳转等浏览器

4. 技术选型

  • JUnit断言
  • Mockitomock数据,数据解耦
  • Robolectric在JVM上运行单测,不须要模拟器or真机
  • Jacoco统计测试覆盖率,便于补充完善单测

5. GET STARTED

  1. 咱们的单元测试基于Robolectric,由于它直接运行于JVM之上,运行单测时速度更快,不须要准备Android环境,不用使用真机||Android模拟器运行测试。当须要进行依赖解耦时,可使用Mock框架
  2. 单元测试主要是针对逻辑进行测试,因此就须要App项目的架构清晰,可测试性好,将UI和逻辑分开,否则的话,仍是先重构吧
  3. 测试代码在app/src/test目录下

5.1 单元测试环境配置(已完成)

  • Robolectric && JUnit:在app/build.gradle中引入
dependencies {
    
    XXXXXX
    
    testCompile 'junit:junit:4.10'
    testCompile 'org.robolectric:robolectric:3.2.2'
    testCompile 'org.robolectric:shadows-multidex:3.2.2'
    
    XXXXXX
}
复制代码
  • Mock配置:在app/build.gradle中引入
dependencies {

    XXXXXX

    testCompile "org.mockito:mockito-core:1.+"
    
    XXXXXX
}
复制代码
  • jacoco:在app/build.gradle中引入
apply from: 'http://git.caimi-inc.com/client/jacoco-plugin/raw/master/jacoco-plugin.gradle'
复制代码
  • 友情提示:在第一次用Robolectric跑单测时,会下载一堆依赖,可能会比较慢

5.2 新建||更新测试用例文档

  1. 若是是给新页面编写单测,须要新建一个单测文档,放在docs/单元测试下:好比是WacaiLoginActivity页面的单测,则文档名为WacaiLoginActivity用例列表
  2. 根据单测文档模板编写对应的测试用例,更新该单测用例文档

5.3 编写测试用例代码

  1. 根据测试用例文档编写测试用例代码
  2. 一个页面||工具类对应一个测试类,用例文档中一个测试用例对应一个测试用例方法

5.4 查看单测覆盖率,以便完善单测

  1. 进入项目所在目录,执行./gradlew jacocoTestReport
  2. 执行成功以后,会在目录app/build/reports/jacoco生成详细的覆盖率报告,使用浏览器打开index.html便可查看
  3. jacoco执行成功以后,同时会将报告上传到pages上,查看地址:pages.wacai.info/client/andr…
    1. 其中,APP_VERSION表示当前应用的版本号versionCode
  4. 若是执行失败,则说明有单测跑不过,须要进行检查,可能缘由:测试用例写得有问题、被测试的逻辑代码有问题、测试框架(配置||环境)有问题
    1. 测试用例有问题:修改测试用例,使之符合正确的逻辑
    2. 被测试的逻辑代码有问题:fix代码逻辑问题
    3. 测试框架(配置||环境)问题:修改配置or环境
  5. 查看单测覆盖率,包括分支覆盖率和行覆盖率
    1. 分支覆盖率:条件执行时不一样的输入条件致使的不一样逻辑走向,最多见的是if-else两个分支,分支覆盖率是指被测试代码覆盖的分支数占整体分支的比例,体现的是不一样输入条件下代码各类边界状况的覆盖状况
    2. 行覆盖率:被测试代码覆盖的逻辑代码行数占整体逻辑代码行数的比例,是一个整体的数值,是一个比较绝对的值
  6. 根据jacoco生成的测试报告不断完善测试用例,直至覆盖全部的分支、边界等。jacoco生成的测试报告很是直观,可以很容易地看出哪些部分的代码被覆盖到了,哪些没有被覆盖到,很方便咱们完善测试用例

5.5 文档式单测流程图

6. 示例:挖财宝-挖财帐号登陆页单元测试实践

为了介绍单元测试的实施过程,下面以挖财宝挖财帐号登陆页做为单元测试实践案例。该案例的开发和测试涉及到了TextView, EditText, Button, Checkbox, ImageView,包含了各类点击、页面跳转等逻辑。页面以下图所示bash

对页面进行单元测试的时候,咱们首先须要分析页面,针对页面提取出业务逻辑,提取出的业务逻辑如上图所示。根据这些逻辑来设计单元测试的case(带有Test注解的被测试方法),业务逻辑包括需求中的业务以及其余的须要维护的代码逻辑。为了减小单元测试case的维护成本,业务流程不容许跨页面,以页面为基本单位。架构

挖财帐号登陆页的单元测试case设计以下:app

目标页面 业务覆盖 界面元素 逻辑描述 最小断言数 case名称
挖财帐号登陆页 WacaiLoginActivity 点击左上角返回 1. 左上角TextView控件 1. 点击左上角TextView控件,关闭结束登陆页 1 testGoBack
输入帐号、密码 1. 帐号输入框(手机/邮箱/帐号)
2. 帐号输入框右侧清空图标ImageView
3. 密码输入框EditText
4. 密码输入框右侧隐藏密码图标ImageView
1. 向帐号输入框输入内容
2. 向密码输入框输入内容
3. 当帐号输入框没有内容时,帐号输入框右侧清空图标ImageView隐藏
4. 当帐号输入框有内容时,帐号输入框右侧清空图标ImageView显示
5. 当密码输入框没有内容时,隐藏密码图标隐藏
6. 当密码输入框有内容时,隐藏密码图标显示
7. 点击清空图标,帐号输入框文本清空
8. 点击隐藏密码图标,密码输入框文本清空
6 testInputAccountAndPassword
点击登陆 1. 登陆按钮
2. 帐号输入框
3. 密码输入框
1. 点击登陆按钮
2. 帐号密码输入框为空,则弹出Toast,页面不跳转
3. 帐号不为空,密码为空,弹出Toast,页面不跳转
4. 帐号密码均不为空,正常登陆逻辑
4 testLogin
自动填充上次登陆用户的用户名 1. 帐号输入框 2. 密码输入框 当用户曾经登陆过期,进入页面会自动在帐号输入框填充上一次登陆成功用户的用户名:
1. 填充帐号输入框
2. 填充以后,密码输入框得到焦点
2 testPastePreAccount
直接点击跳转 1. 右上角注册TextView控件
2. 忘记密码TextView控件
3. 挖财平台注册协议TextView控件
4. 挖财隐私权政策TextView控件
1. 点击注册跳转到手机号注册登陆页面
2. 点击忘记密码跳转到找回密码页面
3. 点击挖财平台注册协议或者挖财隐私权政策,跳转到对应的WebView
4 testJumpDirectly
点击切换是否赞成挖财注册协议 1. 赞成挖财注册协议Checkbox勾选框
2. 登陆按钮
1. 勾选赞成挖财注册协议,则登陆按钮可点击;不然不可点击
2. 进入页面时默认勾选赞成挖财注册协议
3 testAgreeRegisterProtocol

接下来须要在单元测试的工程中实现上述case。最小断言数是从业务逻辑考虑的一个数值,并非代码的边界条件,真实的case须要考虑代码的各类边界状况,好比空指针等,所以,通常实际断言数会大于最小断言数。实际断言数=最小断言数(业务需求断言)+技术需求断言。框架

写完case以后须要跑一遍单测获得单测报告,根据单测报告不断完善单测,提升单测覆盖率。ide

7. 其余问题

  • Robolectric 3.+在各个场景下如何编写测试用例,请查看这里
  • 使用Robolectric 3.+遇到的常见问题汇总,请查看这里

8. 总结

  • 单元测试不是一个可以产生直观可见效益的工程,可是对于保障快速迭代时的代码质量具备重要意义。试想一下,面对一个单元测试覆盖率很高的工程,若是你要进行部分重构的话也会更有信心吧?你每一点对代码的改动,都有可能对其余部分的业务逻辑产生影响,有了单元测试,代码对逻辑的影响能够经过运行单测来断定,若是单测覆盖完备&&单测运行经过,那么就能够认为改动对现有业务逻辑没有影响
  • 项目架构很影响单元测试的实施,井井有条、代码解耦、可测试性好的代码在编写单测的时候是很是舒畅的。若是项目中UI和逻辑高度耦合,代码逻辑都堆在Activity中,那么,你最须要的可能不是单测,而是对项目的重构,各个模块进行解耦、UI和逻辑解耦等
  • 编写代码的时候须要适当考虑代码的可测试性

9. 最后

以上就是文档式单测的内容,目前正在实践之工具

10. 参考资料

相关文章
相关标签/搜索