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

来源:互联网 发布:域名服务器的类型有 编辑:程序博客网 时间:2024/05/21 17:21
http://www.2cto.com/kf/201512/453580.htmlhttp://www.2cto.com/kf/201512/453580.html
http://www.2cto.com/kf/201512/453580.html
http://www.2cto.com/kf/201512/453580.html




Jenkins构建Android项目持续集成之单元测试及代码覆盖率
2015-12-16      0 个评论    来源:画虎烂的专栏  
收藏   我要投稿


单元测试

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

代码覆盖率

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

编写测试用例

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

测试用例

上图写的是一个SharedPreferences Util工具类的测试用例。
如果你的测试用例不想写在这个包下,想自定义,也可以在项目的build.gradle写如下的配置<喎�"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KCjxwcmUgY2xhc3M9"brush:java;">android { sourceSets { androidTest{ java.srcDirs = ['src/com/helen/andbase/tests'] } }

Gradle配置jacoco

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

?
1
<code class=" hljs bash"> apply plugin:'jacoco'</code>

  然后注明使用的版本号

?
1
2
3
<code class=" hljs livecodeserver">jacoco{
        version"0.7.4.201502262128"
    }</code>

  接着,申明一个gradle task

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<code class=" hljs bash">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")
}</code>

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

?
1
2
3
4
5
<code class=" hljs lua">buildTypes {
        debug{
            testCoverageEnabledtrue
        }
    }</code>

  完整的gradle配置如下

?
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
<code class=" hljs livecodeserver">apply plugin:'com.android.library'
//代码覆盖率插件
apply plugin: 'jacoco'
 
android {
    compileSdkVersion22
    buildToolsVersion'22.0.1'
    defaultConfig {
        minSdkVersion8
        targetSdkVersion22
        versionCode1
        versionName"1.0"
    }
    buildTypes {
        release {
            minifyEnabledtrue
            proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
        }
        debug{
            testCoverageEnabledtrue
        }
    }
    lintOptions {
        abortOnErrorfalse
    }
    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'
}</code>

生成报告

配置完上面的步骤之后,打开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报告到邮箱,更进一步的提高代码质量。

0 0
原创粉丝点击