博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android代码单元测试
阅读量:6551 次
发布时间:2019-06-24

本文共 4122 字,大约阅读时间需要 13 分钟。

Android代码单元测试

1. 目的

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

2. 测试用例覆盖范围

一个待测试页面对应多个业务单元,每个业务单元对应一个测试用例,每个测试用例都是一条链路(比如点击一个按钮后产生的一系列直接影响如页面跳转等),实现条件覆盖和路径覆盖。

在Android单元测试中,测试用例不需要覆盖所有的方法逻辑(这也是不太现实的),应该专注于自己编写的业务逻辑等代码的测试覆盖,像 Android SDK 里的方法回调是不需要测试的。

3. 怎样测试逻辑方法

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

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

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

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

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上,查看地址:
    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,包含了各种点击、页面跳转等逻辑。页面如下图所示

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

挖财账号登录页的单元测试case设计如下:

目标页面 业务覆盖 界面元素 逻辑描述 最小断言数 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之后需要跑一遍单测得到单测报告,根据单测报告不断完善单测,提高单测覆盖率。

7. 其他问题

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

8. 总结

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

9. 最后

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

10. 参考资料

转载于:https://juejin.im/post/5c8f4a155188252da179defe

你可能感兴趣的文章
sybase执行计划
查看>>
常用正则表达式大全
查看>>
mybatis插件编写
查看>>
mysql top n 问题
查看>>
sql server 数据库创建链接服务器访问另外一个sql server 数据库
查看>>
SpringBoot1.5.1启动错误
查看>>
虚函数
查看>>
Painter 12安装教程
查看>>
JQuery学习思维导图版
查看>>
maven+spring4+hibernate4 搭建
查看>>
Redis和Memcached的选择
查看>>
servlet,RMI,webservice之间的区别--zhuan tie
查看>>
Lua程序设计--类型与值
查看>>
centos7 gitlab安装
查看>>
hibernate中lazy的使用
查看>>
android jni的JNINativeMethod
查看>>
PHP 获取网页301真实地址
查看>>
免安装的Tomcat基本配置和安装
查看>>
iis配置运行php
查看>>
Eclipse断点调试
查看>>