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報告到郵箱,更進一步的提升代碼質量。

相關文章
相關標籤/搜索