Jenkins构建Android项目持续集成之单元测试及代码覆盖率

单元测试

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

代码覆盖率

  编写好单元测试后,咱们须要知道,测试用例是否覆盖了代码的全部分支状况,这样才能保证代码的可靠性、正确性。java

编写测试用例

若是使用Android Studio建立项目的话,那么默认的会在androidTest包下生成一个ApplicationTest类,在这里面能够写测试用例。android

测试用例

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

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引入插件,语句以下:github

 apply plugin: 'jacoco'
  • 1
  • 1

  而后注明使用的版本号bash

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,须要注意的是,打开该属性的话,在断点调试的时候会致使方法参数值丢失(看不到),因此在调试的时候要记得把它关掉。app

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以后就会自动生成报告。

Android Lint报告

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

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

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

邮件内容修改

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

构建命令修改

项目的build.gradle修改下

build.gradle

去掉connectedAndroidTest的关联,由于咱们已经独立使用命令执行connectedAndroidTest了,因此jenkins服务器在跑job的时候,请确保已经打开了Android模拟器,不然会出错。

查看邮件报告

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

注意:由于个人项目是一个lib项目,而在Android里lib项目生成的jar包是一个aar,因此这里的单元测试,我是写在lib项目里,而后构建产物,我也修改成获取aar包,修改以下: 
构建产物修改 
邮件附件

总结

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

相关文章
相关标签/搜索