单元测试

  在软件开发中一直在推崇TDD(测试驱动开发),但是一直不能被有效的执行或者并不是真正的测试驱动开发(先开发后写单元测试),因为我们懒!而Android开发又是大多应用层面的开发,很多都是和视图层紧密相连的,业务逻辑和view相绑定,这导致编写单元测试有相当大的困难,因此就我项目而言,只针对工具类、服务端API编写单元测试。关于android Studio如何编写单元测试并运行,可以看之前写的一篇文章Android Studio 单元测试

代码覆盖率

  编写好单元测试后,我们需要知道,测试用例是否覆盖了代码的所有分支情况,这样才能保证代码的可靠性、正确性。

编写测试用例

如果使用Android Studio创建项目的话,那么默认的会在androidTest包下生成一个ApplicationTest类,在这里面可以写测试用例。

上图写的是一个SharedPreferences Util工具类的测试用例。 
如果你的测试用例不想写在这个包下,想自定义,也可以在项目的build.gradle写如下的配置

android {
sourceSets {
androidTest{
java.srcDirs = ['src/com/helen/andbase/tests']
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Gradle配置jacoco

  Jacoco是一个开源的覆盖率工具。这里讲下gradle如何配置。 
  首先要在项目的build.gradle引入插件,语句如下:

 apply plugin: 'jacoco'
  • 1
  • 1

  然后注明使用的版本号

jacoco{
version "0.7.4.201502262128"
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

  接着,申明一个gradle task

task jacocoTestReport(type:JacocoReport,dependsOn:"connectedAndroidTest"){
group = "Reporting"
description = "Generate Jacoco coverage reports after running tests."
reports{
xml.enabled = false
html.enabled = true
csv.enabled = false
}
classDirectories = fileTree(
dir : "$buildDir/intermediates/classes/debug",
excludes : [
'**/*Test.class',
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*'
]
)
def coverageSourceDirs = ['src/main/java']
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
additionalClassDirs = files(coverageSourceDirs)
executionData = files("$buildDir/outputs/code-coverage/connected/coverage.ec")
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

  最后,打开testCoverageEnabled,需要注意的是,打开该属性的话,在断点调试的时候会导致方法参数值丢失(看不到),所以在调试的时候要记得把它关掉。

buildTypes {
debug{
testCoverageEnabled true
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

  完整的gradle配置如下

apply plugin: 'com.android.library'
//代码覆盖率插件
apply plugin: 'jacoco' android {
compileSdkVersion 22
buildToolsVersion '22.0.1'
defaultConfig {
minSdkVersion 8
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug{
testCoverageEnabled true
}
}
lintOptions {
abortOnError false
}
packagingOptions {
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
}
jacoco{
version "0.7.4.201502262128"
}
}
//jacocoTestReport依赖于connectedAndroidTest task,所以在执行jacoco之前需要先执行connectedAndroidTest,也就是说需要连接测试机(模拟器or真机)
task jacocoTestReport(type:JacocoReport,dependsOn:"connectedAndroidTest"){
group = "Reporting"
description = "Generate Jacoco coverage reports after running tests."
reports{
xml.enabled = false
html.enabled = true
csv.enabled = false
}
classDirectories = fileTree(
dir : "$buildDir/intermediates/classes/debug",
excludes : [
'**/*Test.class',
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*'
]
)
def coverageSourceDirs = ['src/main/java']
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
additionalClassDirs = files(coverageSourceDirs)
executionData = files("$buildDir/outputs/code-coverage/connected/coverage.ec")
} dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.1'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

生成报告

配置完上面的步骤之后,打开Terminal,并输入命令gradlew jacocoTestReport,回车执行。

之后打开下面的地址,先看下测试结果

 

从上图,可以看到有些测试用例是没有跑通的,点击之后可以看详情信息

根据提示信息,修改代码,直到测试用例跑通之后,如下图:

然后打开下面的地址,如果测试用例没有全部跑通的话,就不会生成代码覆盖率报告。

 

我们去查看下,之前跑的测试用例的覆盖率情况

再点击进去的话,可以看到具体有哪些分支路径是没有覆盖到的。

将报告通过邮箱发送给相关人员

  通过上面的步骤,我们已经可以看到了结果报告,但是,我们的主题是持续集成&自动化,所以,还没有全部完成,我们的主角依然是jenkins。所以,接下来要讲的是:通过jenkins项目配置,让程序自动生成报告,并将结果通过邮件发送给相关人员。

   
   
  先后会创建“Publish JUnit test result report”、”Record JaCoCo coverage report “、“Publish Android Lint results”。

配置单元测试报告

这时候,报了个错误,说当前路径没有匹配到文件,没关系,因为我们还没有执行命令之前,一些文件夹还没有生成,所以可以先忽略。

配置代码覆盖率报告

主要的几个参数配置,“Path to class directories”配置的是编译后.class文件的路径地址,Android都是放在build路径下build\intermediates\classes;“Path to source directories”配置的是Java代码路径。

配置Android Lint报告

Android Lint是Android自带的一个功能,它可以检测一些不规范的写法,并提示。该功能gradle不用配置任何东西,只要执行build之后就会自动生成报告。

上图中不用填写入任何路径,默认的即可。

邮件配置及gradle执行命令的修改

首先,我们先修改下邮件的发送内容。

我们在上一节的基础上,只是新增加了以上3中报告的地址。 
接着,还需要修改gradle 执行的命令。

项目的build.gradle修改下

去掉connectedAndroidTest的关联,因为我们已经独立使用命令执行connectedAndroidTest了,所以jenkins服务器在跑job的时候,请确保已经打开了Android模拟器,否则会出错。

查看邮件报告

配置完以上的步骤之后,将代码push到github上,等待jenkins触发构建或者我们手动执行构建都可以。 
 
邮件里增加了配置里相应修改的内容。

注意:因为我的项目是一个lib项目,而在Android里lib项目生成的jar包是一个aar,所以这里的单元测试,我是写在lib项目里,然后构建产物,我也修改为获取aar包,修改如下: 
 

总结

跟着上面的步骤来,我们就已完成了单元测试及代码覆盖率报告的自动化发邮件了,能及时发现错误,这在很大程度上保证了我们的代码是经测试的,是有效可靠的。下一篇,将讲如何使用findbugs插件进行查虫,包括gradle的配置和jenkins的配置,发送findbugs报告到邮箱,更进一步的提高代码质量。

Jenkins构建Android项目持续集成之单元测试及代码覆盖率的更多相关文章

  1. Jenkins构建Android项目持续集成之findbugs的使用

    Findbugs简介 关于findbugs的介绍,可以自行百度下,这里贴下百度百科的介绍.findbugs是一个静态分析工具,它检查类或者 JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题 ...

  2. 使用jenkins进行Android的持续集成

    关于持续集成的定义和意义可以参考它的 百度百科 主要意义有以下几点: 减少风险 减少重复过程 任何时间.任何地点生成可部署的软件 增强项目的可见性 建立团队对开发产品的信心 持续集成的实施 持续集成的 ...

  3. jenkins部署github项目持续集成

    一.先介绍正向代理和反向代理 正向代理 反向代理 二.安装反响代理得到固定域名 http://www.xiaomiqiu.cn/ 三.Jenkins与Github集成 配置前要求: 1.Jenkins ...

  4. Jenkins + testNg + maven 项目持续集成

    搞了一整天,梳理下关键点: 1.项目的pom.xml要配置插件,同时指定testng.xml文件的位置.就被这个卡了好久 <properties> <maven-surefire-p ...

  5. Net 项目构建基于Jenkins + Github + Mono 的持续集成环境

    Net 项目构建基于Jenkins + Github + Mono 的持续集成环境 阅读目录 1 安装 2 配置 3 测试 在Redhat enterprise 6.5 的服务器上,为在gutub 上 ...

  6. Jenkins +Maven+Tomcat+SVN +Apache项目持续集成构建

    详解Jenkins +Maven+Tomcat+SVN +Apache项目持续集成 一:前言 1. Jenkins jenkins版本大全http://mirrors.jenkins-ci.org/ ...

  7. Framework项目持续集成(jenkins)及集合SonarQube

    目录 Framework项目持续集成及集合SonarQube - 前言 CI/CD是什么 -- jenkins 什么是sonarqube?什么是CodeReview? 什么是sonarqube? 什么 ...

  8. Selenium Web 自动化 - 项目持续集成(进阶)

    Selenium Web 自动化 - 项目持续集成(进阶) 2017-03-09 目录 1 背景及目标2 环境配置  2.1 SVN的安装及使用  2.2 新建Jenkins任务3 过程分析 1 背景 ...

  9. Selenium Web 自动化 - 项目持续集成

    Selenium Web 自动化 - 项目持续集成 2017-02-13 目录 1环境准备  1.1 安装git  1.2 安装jenkins  1.3 安装jenkins插件  1.4 jekins ...

随机推荐

  1. Tomcat 安装与配置

    1. 将压缩文件“apache-tomcat-7.0.62.zip ”上传到linux系统目录:/home/下 2. 进入目录 cd /home/ 解压文件,执行如下命令:unzip apache-t ...

  2. python爬虫从入门到放弃(四)之 Requests库的基本使用

    什么是Requests Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库如果你看过上篇文章关于urllib库的使用,你会发现,其 ...

  3. javascript基础-语法

    代表此属性ECMAScript 5(一般IE9+)才支持. 图解:—— 图解: undefined,null,NaN Infinity ECMAScript 5禁止修改 每个函数都是Function的 ...

  4. DRBD+Heartbeat+Mysql高可用读写分离架构

    声明:本案例仅为评估测试版本 注意:所有服务器之间必须做好时间同步 架构拓扑 IP信息: Heartbeat安装部署 1.安装heartbeat(主备节点同时安装) [root@master1 ~]# ...

  5. Oracle体系结构之进程

    Oracle体系结构之进程 一.概述 Oracle中的每个进程都要执行一个特定的任务(或者一组任务),每个进程都会为自己分配内存(PGA)来完成它的任务.一个Oracle实例主要有以下3类进程: (1 ...

  6. 基于FPGA的彩色图像转灰度算法实现

    昨天才更新了两篇博客,今天又要更新了,并不是我垃圾产,只不过这些在上个月就已经写好了,只是因为比赛忙,一直腾不出时间整理出来发表而已,但是做完一件事情总感觉不写一博文总结一下就少点什么,所以之后的一段 ...

  7. Lucene全文搜索之分词器:使用IK Analyzer中文分词器(修改IK Analyzer源码使其支持lucene5.5.x)

    注意:基于lucene5.5.x版本 一.简单介绍下IK Analyzer IK Analyzer是linliangyi2007的作品,再此表示感谢,他的博客地址:http://linliangyi2 ...

  8. DiscuzX3.1搬家全过程

    最近做了一个安全交流小社区,由于太卡了,之后换了服务器,要给论坛搬家 所以在这里写一下记录. 首先,搬家前要做好以下准备: 1.在网站后台-站长-数据库-备份-网站-Discuz! 和 UCenter ...

  9. Compare and Swap [CAS] 算法

    一个Java 5中最好的补充是对原子操作的支持类,如AtomicInteger,AtomicLong等.这些类帮助你减少复杂的(不必要的)多线程代码,实际上只是完成一些基本操作,如增加或减少多个线程之 ...

  10. 解决laydate时间日期插件定位溢出

    laydate是一款比较好用的网页时间日期插件,不过用起来有一些细节问题需要我们手动去解决!例如:laydate兼容bootstrap 1. 默认情况 laydate弹出层默认对齐input左边框 2 ...