--- title: 在 Gitlab 上建立 Java Unit Test tags: CI/CD, Gitlab, Java, Unit Test, Gitlab Runner description: 在 Gitlab 使用 Runner 執行 Java 的 Unit Test. --- # 在 Gitlab 上建立 Java Unit Test 這裡我使用簡單的最簡單的範例,在 Gitlab 上實作一個 Java Unit Test,以下是我使用的環境: * 語言: Java * 專案管理: Maven * 程式碼編輯器: VSCode * Runner 作業系統: Windows10 * 最後更新日期 :2021/08/08 --- ## Chapter 1. 簡單的 Java 單元測試 ### Step 1. 安裝 Maven Apache Maven,是一個軟體(特別是Java軟體)專案管理及自動構建工具,由Apache軟體基金會所提供。這裡我使用 Maven 作為我的 Java 專案管理及自動構建工具。 安裝的過程非常非常的簡單,首先先去官網 [Apache Maven Download](https://maven.apache.org/download.cgi)頁面下載<font color="red">紅框處</font>的檔案。 ![Maven 下載頁面](https://i.imgur.com/A10VgQO.png) 下載完後請解壓縮,解壓縮後會看到以下的檔案,可以將這整個資料夾放置在任何地方,只要你知道這個資料夾位置就好。以我的範例來說我放在 C 槽目錄: ![Maven 檔案放置位置](https://i.imgur.com/BJ8vPAu.png) 接下來,進入到 bin 資料夾,把路徑複製下來,以我的範例來說就會是==C:\apache-maven-3.8.1\bin==,接下來請去**系統變數**那邊,將這個路徑新增進去,之後開啟 windows cmd,輸入 ==mvn -v==,當有看到以下訊息時,代表你安裝成功了。 ![Maven 安裝成功訊息](https://i.imgur.com/1DSb15x.png) --- ### Step 2. 新增一個 Java 專案 開啟 Visual Studio Code,去 Extensions 裡安裝,==Java Extension Pack==,基本上裡面重要的東西都有包含到,所以直接 install 就好了。安裝完後重啟 VSCode,按 Explorer,應該就會看到左下角有個 Maven 文字,點他後會展開,再點旁邊的 ==+== 號 ![Maven 新增專案](https://i.imgur.com/qZ1hViA.png) 這裡我使用 ==Maven-archetype-quickstart== 且版本為 ==1.4== 作為範例專案,如果有其他需求可以點其他的樣板。 ![Maven QuickStart](https://i.imgur.com/aPoXA4P.png) 之後就輸入你的 Group ID、Artifical ID,輸入完後會要你選擇專案的根資料夾,放在哪裡都可以,建議路徑不要有中文、空白或特殊字元就好,之後再輸入版本號,輸入為會看到以下畫面,再輸入 Y 做專案的確認: :::info 第一次執行會跑比較久,請耐心等候 ::: ![Maven Comfirm](https://i.imgur.com/CIa1nq5.png) 跑完後在使用 Visual Studio Code 開啟剛剛專案建立的資料夾,就會看到以下的畫面,這樣專案就算建立成功了: ![Maven Project Folder](https://i.imgur.com/yxBXXY3.png) --- ### Step 3. 第一次推送至 Gitlab 因為剛剛新增了一個專案,接下來我們要把他推送至 Gitlab 先執行: :::warning 請記得先 git clone 至本地,在執行以下指令。如果可以 .gitignore 也可以先加入至專案 ::: ==.gitignore== 檔的內容(這個要自己手動加入) ``` target/ pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup pom.xml.next release.properties dependency-reduced-pom.xml buildNumber.properties .mvn/timing.properties .mvn/wrapper/maven-wrapper.ja ``` 第一次推送至 Gitlab ```shell= git init //初始化 git git add -all //把專案新增的檔案加入 git commit -m "project create" //commit 檔案 ``` 成功後去 Gitlab 的專案就可以看到以下結果了 ![](https://i.imgur.com/FzmwWKk.png) --- ### Step 4. 執行程式 首先先在 ==App.java== 裡撰寫一些簡單的功能: ```java= package com.devop; /** Simple Hello World **/ public class App { public static final String KEY = "Peko"; // 假裝是個密碼 private String keyToken; public static void main( String[] args ){ System.out.println( "Hello World!" ); App app = new App(); System.out.prinln( "2 * (3 + 5) = " + (2 * app.sum( 3, 5 )) ); app.registerToken( "Peko" ); System.out.println( app.getKeyToken() ); } /** * 簡單的加法 * @param a A數字 * @param b B數字 * @return 總和結果 */ public int sum(int a, int b){ return a + b; } /** * 設定密碼金鑰 * @param input 金鑰 */ public void registerToken(String input){ this.keyToken = input.replace("Pe", "Mi"); } /** * 取得註冊的 Token * @return Token */ public String getKeyToken(){ return this.keyToken; } } ``` 這時我們可以先開啟 VSCode 的 Terminal(終端機),來執行上方的程式, 並且在終端機輸入以下指令。 編譯程式: ```shell= mvn compile ``` 執行主程式: ```shell= mvn exec:java -D"exec.mainClass"="{專案package}.App" //執行 ``` 上面的指令以我的範例就會變成 :::success mvn exec:java -D"exec.mainClass"="<font color="red">com.devop</font>.App" ::: 輸入完後就會看到以下的畫面了: ![Maven Execute](https://i.imgur.com/xDKadp5.png) --- ### Step 5. 撰寫單元測試 在大多數的大型專案中,當一個專案的功能持續的增多,在測試上難免會花費不少時間,尤其是當修改 A 功能時,B 功能受到影響而產生 BUG,這個在大型專案中是非常容易發生的。這也就是為什麼要寫單元測試去執行各個元件的功能,以保持程式的正確性。 首先去 ==AppTest.java== 裡新增單元測試的條件: ```java= /** * Unit test for simple App. */ public class AppTest { private App app; public AppTest(){ System.out.println( "\nAppTest Start... " ); this.app = new App(); this.app.registerToken( "Peko" ); } /** * Rigorous Test :-) */ @Test public void shouldAnswerWithTrue(){ assertEquals( 15, app.sum(10, 5) ); // 驗證加法運算是否有出錯 } @Test public void checkKeyToken(){ assertEquals( App.KEY.replace("Pe", "Mi"), app.getKeyToken() ); System.out.println( "Do other things here..." ); } } ``` 接下來只要在終端機輸入: ```shell= mvn test ``` 經過單元測試的結果: ![Maven Test](https://i.imgur.com/Sbudz5M.png) 假如這時候我們在修改 ==App.java== 的 ==sum 函式==時,不小心把它改成 ==a * b==,這時候我們在執行一次 ==mvn test==,就會出現以下的結果: ![Maven Test Failed](https://i.imgur.com/rdUSbEB.png) 根據以上的結果,當我們在執行單元測試時,就可以知道 ==App.java== 的 ==sum 函式== 寫錯了,這樣我們就可以很快地更正他。 --- ## Chapter 2. 在 Gitlab 上佈署自動測試 ### Step 1. 在 Gitlab 上建立 CI/CD 檔 這裡我就不講 CI/CD 的原理以及概念了,簡單來說就是能讓整個專案在測試、佈署、建置都能自動化,並且可以監控狀態。這裡我用 Gitlab 作為 CI/CD 的平台。 首先,先新增一個檔案 ==.gitlab-ci.yml== 放在上面 push 的專案跟目錄裡,內容打: ```yaml= stages: # 定義有哪些 stages - build - refactoring - test - deploy build-project: # stage 名稱 stage: build tags: - main-runner # 可執行的 runner tag only: - master # 可執行的分支(branch) script: - echo "Hello Peko" # 簡單的印出 build-project-issue: stage: build tags: # 可以多個 tag - main-runner - issue-runner only: - issue script: - echo "building issue" refactoring-project: stage: refactoring tags: - main-runner only: - refactor script: - echo "refactoring program" test-project: stage: test tags: - main-runner only: # 可以多個 branch - master - issue - refactor script: - echo "simple unit test" deploy-project: stage: deploy tags: - main-runner only: - master script: - echo "package the project" ``` :::info 這個內容只是範例用的,之後都可以自行的修改它! ::: 再來我各個講解 .yml 裡的功能與定義,首先: * **stages** (第1行) > 代表的是在進行階段,當前一階段通過時,才能進行下一階段。依照我們這個範例意思就是當在自動測試時,會先執行 **build -> test -> deploy**,如果在 **test** 失敗時,就會直接停止,就不會執行 **deploy** 了 * **build-project** (第7行) > 這裡就是在定義各個 **stage** 的細節,這裡的 **build-project** 是 **stage** 名稱,要怎麼取都可以,只要看得懂且能執行就好。 >>* **stage** (第8行) >> 這裡定義這個 **stage** 是哪一個階段,必須要跟上面 "**stages** (第1行)" 的名稱匹配。 > >> * **tags** (第9行) >> 這個定義的是給 Runner 的標籤,假如我們想讓特定 Runner 只能執行某些 **stage** 就可以利用這個做設定。 > >> * **only** (第11行) >> 這個是用來定義在哪些的 **分支(Branch)** 才會執行此 **stage**。 > >> * **script** (第13行) >> 這個是指 Runner 在進行測試時,會執行的指令,這個會根據作業系統而做不同的改變,像是這裡我 Runner 預設是 Windows 的 powershell,所以當在執行時就會執行以下指令 **powershell echo "Hello Peko"** 基本上以上就是最基本的 **.gitlab-ci.yml** 的設定,剩下的 **test-project**、**test-project-issue**、**deploy-project** 也都是相同的概念,如果要在有更複雜的功能可以自行去搜尋。 當建立好 **.gitlab-ci.yml** 之後,請記得 push 至 Gitlab,這時候去 Gitlab 專案裡的 **CI/CD** 就可以看到以下結果: ![Gitlab Pending](https://i.imgur.com/J2UctVt.png) :::warning 這裡可以不用等它,不管怎麼等都只會卡在 pending,所以請繼續看下去。 ::: --- ### Step 3. 下載 Runner 主程式 首先,先去先前的專案裡的 **Settings** -> **CI/CD** -> **Runners** (點擊右邊展開)。 :::warning 假如你的專案沒有 **Settings** 的話,請確認是否你具有對此專案權限喔。 ::: 去 Gitlab 官網下載 Runner 的主程式,看你的作業系統就下載哪個,以我的來說是 Windows 10 64位元,所以我就點 **Binaries** -> **Install on Windows** -> **64-bit** ![Donwload Runner](https://i.imgur.com/CGa4KMR.png) 下載完後,檔案會是個 **gitlab-runner-windows-amd64.exe** 檔,這時請 **建立一個資料夾**,放在哪裡都可以,把這個 **gitlab-runner-windows-amd64.exe** 放到資料夾裡,資料夾的名稱可以自由的取,以英文為主就好。 --- ### Step 4. 註冊 Runner 以我的來說,我是放置在 **D:\ProgramPackage\GitLabRunner** 這個路徑下,接下來開啟 **cmd(命令提示字元)** ,指到剛剛放置 **gitlab-runner-windows-amd64.exe** 的資料夾。接下來執行以下指令: :::warning 請記得要以系統管理員執行 **cmd** ::: 安裝 gitlab-runner-windows-amd64.exe ```shell= gitlab-runner-windows-amd64.exe install ``` :::danger 第一次執行此程式的時候或更動了 .exe 位置時都要執行此命令!之後註冊就不用執行了。 ::: 註冊 Runner ```shell= gitlab-runner-windows-amd64.exe register ``` 接下來依序填入 * **網址** (第一個紅框處) > Enter the GitLab instance URL (for example, https://gitlab.com/) * **Token** (第二個紅框) > Enter the registration token: * **此 Runner 的描述** > Enter a description for the runner * **此 Runner 的 Tag** (逗號分隔,用於多個 Tag) > <font color="red">根據我們前面的 .gitlab-ci.yml 設定,這用 main-runner 作為 Tag</font> > Enter tags for the runner (comma-separated): * **此 Runner 的執行器** (通常只要打 shell 就好) > Enter an executor ![Fill Runner](https://i.imgur.com/XwXzcDM.png) 註冊完後會看到的畫面: ![Runner Finish Register Cmd](https://i.imgur.com/iWhj1rb.png) 之後去 Gitlab 的 Runner 下方就會看到剛剛註冊的 Runner 跑出來了 ![Runner Finish Gitlab](https://i.imgur.com/irk4Et2.png) --- ### Step 5. 執行 Runner 經過上述步驟後,只是完成了註冊,還沒讓 Runner 執行起來,接下來一樣在 **cmd(命令提示字元)** 輸入以下的指令: ```shell= gitlab-runner-windows-amd64.exe verify //驗證 gitlab-runner-windows-amd64.exe start //啟動 gitlab-runner-windows-amd64.exe run //執行 ``` :::danger 注意!上面的每一行指令都是不可或缺的,只要你重新啟動 Runner 都要執行一遍 ::: 這時 **cmd(命令提示字元)** 會顯示以下訊息: ![Runner start cmd](https://i.imgur.com/z17OUWY.png) :::info 執行後停在這邊是正常的,別在意。 ::: 接下來可以嘗試 Push 一次至 Gitlab 看執行的狀況 **CI/CD** -> **Pipelines** 。基本上假如你是 Windows 的話,第一次都會失敗,並且 **cmd(命令提示字元)** 會顯示以下訊息: ![PowerShell Error cmd](https://i.imgur.com/tFysEmG.png) 這個的解決方法為,到 **gitlab-runner-windows-amd64.exe** 的根目錄裡,找到一個名為 ==config.toml== 的檔案,把 **shell = "pwsh"** 改成 **shell = "powershell"**,然後去 **cmd(命令提示字元)** Ctrl+C 跳出,執行以下指令來停止 Runner: ```shell= gitlab-runner-windows-amd64.exe stop ``` 之後在執行上面的三條指令,來開啟 Runner,然後再 Push 一次就會顯示成功了: ![Gitlab pipeline success](https://i.imgur.com/2lStruv.png) 點進去 **Stage** 可以看到它執行的結果,以我們的例子就可以看到底下的結果: ![Gitlab Stage success](https://i.imgur.com/27EuaU3.png) --- ### Step 6. 將單元測試讓 Runner 執行 想要讓把 Java 的自動整合放到 Gitlab 上的方法,非常簡單,根據我們以上的範例只要改動 ==.gitlab-ci.yml== 裡的設定就可以了,以下是改動後的結果 **(這裡我只改動 script 而已,其餘的都一樣)**: ```yaml= stages: - build - refactoring - test - deploy build-project: stage: build tags: - main-runner only: - master script: - mvn compile # mvn 編譯程式指令 build-project-issue: stage: build tags: - main-runner - issue-runner only: - issue script: # 可以多個 script - mvn clean # mvn 專案清空 - mvn compile # mvn 重新編譯 refactoring-project: stage: refactoring tags: - main-runner only: - refactor script: - mvn clean - mvn compile - mvn verify test-project: stage: test tags: - main-runner only: - master - issue - refactor script: - mvn test # mvn 單元測試指令 deploy-project: stage: deploy tags: - main-runner only: - master script: - mvn package # mvn 專案打包 ``` 接下來去 Gitlab 的 **Pipelines** 就可以看到執行結果了: ![maven result on gitlab](https://i.imgur.com/SCqe1Iu.png) 可以看到這裡的輸出變成了 **Maven** 的訊息,接下來我們可以試試單元測試是否有效。一樣 修改 ==App.java== 的 ==sum 函式==,把它改成 ==a * b== 之後,再次 Push 察看結果。以下是更改後會跳出的結果: ![maven unit test failed on gitlab](https://i.imgur.com/894B8Ur.png) 我們可以看到推送至 Gitlab 上的新的程式碼在進行 **Testing** 的時候 <font color="red">**failed**</font> 了,這也就代表我們設定的單元測試有用,並且在撰寫來源程式碼時寫錯了邏輯。 大致上這就是整體的流程,剩下的 **分支(Branch)** 就留給各為自己去測試了,基本上流程相同,指不握要先建立分支,然後再推送,大致上流程都差不多。假如要在自動整合的部分有更多不同的功能可以在自己去研究。 # 結論 CI/CD 已經是目前程式開發的趨勢之一,擁有這些知識對於日後管理與開發進度上都會有很大的優勢。目前在 Gitlab 上提供的 CI/CD 功能已經非常的實用了,很適合在測試不同情況下的程式碼,也能適時地追中這些程式碼是否是有效的,也能讓多人開發上更為的便利。