﻿# 如何在 Spring Boot 與 Maven 專案加入 JaCoCo 測試覆蓋率報告 (VSCode)

最近已經把 [Java in Visual Studio Code](https://code.visualstudio.com/docs/languages/java) 摸索到一定程度，但是獨缺 Test Coverage Report 報告可看。這篇文章我打算分享如何在專案中加入 [JaCoCo Java Code Coverage Library](https://www.jacoco.org/jacoco/)，並透過微軟最新推出的 [Live Preview](https://marketplace.visualstudio.com/items?itemName=ms-vscode.live-server) 這個 VSCode 擴充套件查看報告。

### 測試覆蓋率報告設定步驟

雖然 [JaCoCo](https://www.jacoco.org/jacoco/trunk/index.html) 有個 [Maven Plug-in](https://www.jacoco.org/jacoco/trunk/doc/maven.html) 可用，不過官網文件寫的真的很不清楚。以下是產生測試覆蓋率報告的完整設定步驟：

1.  加入 `jacoco-maven-plugin` 外掛的 Maven 設定到 `pom.xml` 檔案中
    
    請加入以下片段到 `<build>` 的 `<plugins>` 區段下：
    
    ```xml
    <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.8.7</version>
        <executions>
            <execution>
                <id>default-prepare-agent</id>
                <goals>
                    <goal>prepare-agent</goal>
                </goals>
            </execution>
            <execution>
                <id>default-report</id>
                <goals>
                    <goal>report</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    ```
    
    請加入以下片段到 `<reporting>` 的 `<plugins>` 區段下：
    
    ```xml
    <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.8.7</version>
    </plugin>
    ```
    
2.  使用 [Maven for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-maven) 執行測試
    
    ![執行測試](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/260cd2b3b3f601468329-128891890-ee59387b-9069-4ecf-8a61-643aa5df7ba8.png)
    
    執行測試的過程會產生一個**測試覆蓋率報告**，檔案路徑為 `target/jacoco.exec`，這是一個 binary format 的檔案，我們沒辦法直接閱讀其內容，但有一些第三方工具是可以解析這個檔案的，例如。
    
    > [Sonar Qube](https://docs.sonarqube.org/latest/analysis/coverage/) 可以利用這個檔案產生**測試覆蓋率報告**與**程式碼複雜度報告**，詳細步驟請參見 [Code Coverage with SonarQube and JaCoCo](https://www.baeldung.com/sonarqube-jacoco-code-coverage) 文章。
    
    還好我們在 `jacoco-maven-plugin` 外掛中可以找到一個 [jacoco:report](https://www.jacoco.org/jacoco/trunk/doc/report-mojo.html) 目標，執行這個目標就會自動產生 HTML, CSV 與 XML 格式的**測試覆蓋率報告**，檔案路徑位於 `target/site/jacoco/` 目錄下，其中有個 `index.html` 就是我們 HTML 報告的主要檔案。
    
    ![我們在 jacoco-maven-plugin 外掛中可以找到一個 jacoco:report 目標](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/1021030a17c4495ad081-128891884-3e559013-8682-4c4b-830e-8e24d50d95de.png)
    
    > 注意：`jacoco-maven-plugin` 外掛的 [jacoco:report](https://www.jacoco.org/jacoco/trunk/doc/report-mojo.html) 目標，預設綁定到 `verify` 生命週期階段([lifecycle phase](http://maven.apache.org/ref/current/maven-core/lifecycles.html))，所以當你執行 `mvn verify` 的時候，也會自動執行測試並產生報告：
    
    ![執行 verify 動作自動執行測試並產生報告](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/e78861e442a91431721d-128891888-fbc229f9-876b-47c7-9327-0a7df03ccee9.png)
    
3.  安裝 VSCode 的 [Live Preview](https://marketplace.visualstudio.com/items?itemName=ms-vscode.live-server) 擴充套件
    
4.  找到 `target/site/jacoco/index.html` 檔案，按下滑鼠右鍵，點擊 **Live Preview: Show Preview** 就可以產生即時預覽畫面！
    
    ![Live Preview: Show Preview](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/d5d740008d0c70bfbe96-128892378-bd9d7fed-85aa-480b-9f1f-09aed6cc02ed.png)
    
    此時你就可以看到非常清楚的**測試覆蓋率報告**：
    
    ![測試覆蓋率報告](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/1c24b007ca13ca584da9-128892903-3b1ed467-8e94-4418-8e2c-1c0719f4086e.png)
    
    ![測試覆蓋率報告](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/cf63140b459359c17133-128954389-87dd484c-8f69-4959-b716-fdb3ef70bb56.png)
    
    ![測試覆蓋率報告](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/432b8492ec39cc3a19a2-128954684-51b73a96-3fa2-4628-a0ad-a79e266c7600.png)
    
    ![測試覆蓋率報告](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/0f055dd1db9b3f6a4397-128954924-3f9963fb-ca02-4460-86ac-32fe8542c789.png)
    
    最後一張圖片顯示的事 JaCoCo 報表對於特定方法的分析狀況，幫你你用比較視覺化的方式理解程式碼覆蓋率。其中「**有底色**」的部分顯示的是每一行程式碼的覆蓋率情形。而有些地方會出現「**鑽石**」則代表程式邏輯包含了**分支**，會需要多個**測試案例**才能完整覆蓋這些地方。
    
    以下是不同鑽石顏色代表的意義：
    
    -   紅色鑽石 (Red diamond) 代表這個分支並沒有被測到。
    -   黃色鑽石 (Yellow diamond) 代表這個分支只有被部分覆蓋到，有些分支沒有測到。
    -   綠色鑽石 (Green diamond) 代表所有分支都有被完整測試到。

### 閱讀測試覆蓋率報告

表格上的欄位介紹：

-   Element
    
    代表報告項目的對象，可能是 package 或 class 或 method，有連結的話可以點擊進去看更細部的報告。
    
-   Missed Instructions
    
    這部分又稱 **Lines coverage**，但這裡指的 **Lines** 是指 Java bytecode 的指令集數量，而非 Java 的程式碼數量。
    
    紅色部分代表未被測試覆蓋的測試程式碼 (bytecode instructions)，綠色代表有測試到的比例。
    
    旁邊的 `Cov.` 代表**測試覆蓋率**。
    
-   Missed Branches
    
    這部分又稱 **Branches coverage**，但這裡指的 **Branches** 是指「判斷式」的分支數量，如果你的程式碼中有個 `if` / `else` / `switch` 語句，裡面用到的所有判斷式，那麼對程式邏輯來說，這就是一個「分支」，如果你的測試案例不夠多，可以測試到的「分支」就自然會有所缺漏，這裡就是顯示出你有多少「分支」沒有被測試到。
    
    代表沒有測到的**分支**比例。這裡的「分支」就是
    
    旁邊的 `Cov.` 代表**分支覆蓋率**。
    
-   Missed / Cxty
    
    這部分又稱 **Cyclomatic complexity** (循環複雜度)，意味著程式碼有多複雜，你要經過多少路徑才能測過所有程式碼。
    
    如果 Missed / Cxty 分別是 61 / 66 的話，那麼就代表這個 package 有 66 條不同的路徑，但有 61 條路徑都沒有測試到。如果有某個方法 (method) 完全沒有 `if` 或 `switch` 判斷式，那麼這個程式的 **複雜度**(complexity) 為 `1`。
    
-   Missed / Lines
    
    這裡的 Lines 就真的是 Java 程式碼的**行數**了，而非 Bytecode 的指令集數量。Missed 就是沒有測試到的數量。
    
-   Missed / Methods
    
    這裡的 Methods 指的是類別中的**方法**數量。Missed 就是沒有測試到的數量。
    
-   Missed / Classes
    
    這裡的 Classes 指的是**類別**的數量。Missed 就是沒有測試到的數量。
    

### 相關連結

-   [JaCoCo Java Code Coverage Library](https://www.jacoco.org/jacoco/trunk/index.html)
    -   [Maven Plug-in](https://www.jacoco.org/jacoco/trunk/doc/maven.html)
    -   [jacoco/jacoco: Java Code Coverage Library](https://github.com/jacoco/jacoco)
-   [Intro to JaCoCo | Baeldung](https://www.baeldung.com/jacoco)
-   [Code Coverage with SonarQube and JaCoCo](https://www.baeldung.com/sonarqube-jacoco-code-coverage)
-   [Maven Getting Started Guide](http://maven.apache.org/guides/getting-started/index.html)
