Jenkins構建Android項目持續集成之單元測試及代碼覆蓋率

單元測試

  在軟件開發中一直在推崇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']
        }
    }

Gradle配置jacoco

  Jacoco是一個開源的覆蓋率工具。這裏講下gradle如何配置。
  首先要在項目的build.gradle引入插件,語句如下:

 apply plugin: 'jacoco'

  然後註明使用的版本號

jacoco{
        version "0.7.4.201502262128"
    }

  接着,申明一個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")
}

  最後,打開testCoverageEnabled,需要注意的是,打開該屬性的話,在斷點調試的時候會導致方法參數值丟失(看不到),所以在調試的時候要記得把它關掉。

buildTypes {
        debug{
            testCoverageEnabled true
        }
    }

  完整的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'
}

生成報告

配置完上面的步驟之後,打開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報告到郵箱,更進一步的提高代碼質量。

看下其他文章:
1、Jenkins構建Android項目持續集成之簡介篇
2、Jenkins構建Android項目持續集成之Jenkins的安裝篇
3、Jenkins構建Android項目持續集成之系統配置篇
4、Jenkins構建Android項目持續集成之創建項目
5、Jenkins構建Android項目持續集成之單元測試及代碼覆蓋率
6、Jenkins構建Android項目持續集成之findbugs的使用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章