iT邦幫忙

2

【 Java Unit Test學習】- 手把手寫 Java Unit Test單元測試,建立程式碼防護網 (1)

  • 分享至 

  • xImage
  •  

首頁圖
你有過這種經驗嗎?明明只改了一行看似無關緊要的代碼,結果上線後,接到系統崩潰的電話,翻遍整個專案才發現問題只是刪了不該刪除的判斷!

不聊深奧的架構,我們來手把手建立起那道讓晚上能安心睡覺的"第一道代碼防護網"!

此篇我們可以學到 :

  1. 為何要寫Unit Test
  2. 寫出屬於自己專案的 Unit Test

為何要寫 Unit Test :

  • 省錢(早期糾錯): 在開發階段修 Bug 只要幾分鐘;上線後修 Bug 可能要因為此錯誤需修正資料、排除後續異常,動員整個團隊處理 (筆者還曾經在會計人員旁罰站~^^ )。

  • 省心(重構保障): 當我們修改舊程式碼時,測試就像「防護網」,一鍵通知是否不小心弄壞了別的功能。

  • 省力(活的文件): 測試案例直接示範了程式碼「該如何運作」,比任何過時的開發文件都更可靠,也有現行參數可以測試使用。


寫出屬於自己專案的 Unit Test

下列為我們案例會使用的程式碼
GitHub : https://github.com/KuangHung/java.git
IDE : IntelliJ IDEA Community Edition
JDK : Oracle Open Jdk 21.0.3

首先,Unit Test 使用的套將維護在 pom.xml 中

  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <scope>test</scope>
  </dependency>

IDE 的 JDK 可由此路徑確認
2
3

確定好環境後,我們就可以開始撰寫第一段程式碼,下列程式碼為取得 Cookie 的資料,並且印出 Cookie 的 User Name 案例

 @GetMapping("/getCookie")
 public String getCookie(HttpServletRequest request) {
  String username = "";
  System.out.println("getCookie");
  Cookie[] cookies = request.getCookies();
  if (cookies != null) {
   for (Cookie cookie : cookies) {
    System.out.println(cookie.getName());
    if ("username".equals(cookie.getName())) {
     username = cookie.getValue();
     // 在這裡處理 Cookie 的值
     break;
    }
   }
  }
  System.out.println("getCookie username : "+username);
  return username;
 }

通常,如果此段程式碼會做為 API 使用,因此我們需要透過第三方工具如 Postman 或真正啟動一個網頁前端,才能打到後端 API ,費時又費力。

此時我們可以考慮直接寫一個對應的 Unit Test 來直接測試程式,案例程式如下 :
4
藍框為被測試的程式,紅框為測試的 Unit Test

 // 為需要被測試的該支程式,我們會需要設定,此設定將模擬的 Mock 物件注入到測試目標
 @InjectMocks
 private HelloController helloController;

 // 用來模擬被測試的程式中,所有伺服器的請求
 @Mock
 private HttpServletRequest request;

 // 執行Unit Test ,初始化所有的 Mock 
 @Before
 public void setup() {
  MockitoAnnotations.initMocks(this);
 }

 /**
  * 測試用途:驗證 Controller 是否能正確從 Cookie 中提取 username
  */
 @Test
 public void getCookie_Test() {
  String username = "john_doe";

  // 1. 建立一個模擬的 Request 物件
  request = Mockito.mock(HttpServletRequest.class);

  // 2. 定義行為:當呼叫 getCookies() 時,回傳內含指定 username 的 Cookie 陣列
  Cookie[] cookies = {new Cookie("username", username)};
  Mockito.when(request.getCookies()).thenReturn(cookies);

  // 3. 執行測試目標方法
  String result = helloController.getCookie(request);

  // 4. 驗證:結果不應為空,且必須等於預期的內容
  Assert.assertNotNull(result);
  Assert.assertEquals(username, result);
 }

執行第一次測試 :
5

將可以看到測試後,被測試的程式碼會有顏色標註,綠色代表此次測試有涵蓋,紅色則代表此次測試沒有執行到的部分。
6
7
測試結果符合預期,將顯示率勾勾。

此時,我們執行完第一個案例,並且這個 Unit Test 案例執行為 Pass,接下來逐步解說我們如何完成測試的部分 :

8

  1. 在 getCookie_Test 中,行 45 執行並接收測試的回傳資訊。
  2. 實際測試執行 getCookie 時,執行到行 40 時 (紅框),將回傳 getCookit_Test 建立的 cookie (藍框)。
  3. 回到 getCookie_Test 行48、49,可以驗證程式執行後回傳的資料是否正確。

接下來我們來假設,程式改錯了,所以應該要觸發 Unit Test測試失敗
9

可以看到,行 44 的 username 在無意中新增了一個 _ ,此時去執行 Unit Test,將會顯示失敗。

可以看到,我們的Unit Test 示警,並且提示應該回傳的正確資料,與實際回傳的資料差異,藉此我們可以透過這個問題去回追程式哪邊有問題。


總結 :

感謝你花時間看完了這篇分享。建立防護網的過程雖然需要多花心思,但這絕對是讓我們從『忙著救火』轉向『穩定開發』最值得的投資 。

希望這篇文章能讓你少走一點彎路,早點寫完程式、安心下班。如果在實作 Unit Test 遇到任何困難,或是也曾有過那種『在會計人員旁罰站』的慘痛回憶 ,歡迎在下方留言跟我分享,我們一起避坑!

其他的學習文章


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言