Unittest
單元測試 Unit testing
目的: 自動化測試程式的正確性
所謂的單元測試 ,就是一次只測試一個功能點 ,一個單元 Unit 可以是一個 method ,或是一個API

其他軟體測試:
- 整合測試 (Integration testing)
- 端對端測試 (end-to-end testing)
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
單元測試實作
創建一個 Calculator 的 class
package com.example.demo.UnitTest;
public class Calculator {
public int add(int x ,int y){
return x - y;
}
public static void main(String[] args) {
Calculator calculator = new Calculator();
int result = calculator.add(1,2);
System.out.println(result);
}
}
快速創建一個 Test

Test 的 class
assertEquals 判斷說 (預期 , calculator.add() 方法的結果) 是否相等
package com.example.demo.UnitTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CalculatorTest {
@Test
public void test(){
Calculator calculator = new Calculator();
int result = calculator.add(1,2);
assertEquals(3,result); // assert 斷言 Equals 相等
}
}
顯示畫面
成功

失敗

單元測試的特性
- 可以被自動化運行
- 各個單元測試互相獨立 ,彼此之間不能有依賴關係
- 測試的結果是穩定的 , 不受外部服務影響
單元測試的注意事項
- 測試的程式要放在test資料夾裡面 (方便管理程式)
- src (source)
- main 放我們要寫的code
- java 放 java code
- resources 放 Spring Boot 設定檔
- test 放測試用的code
- java 放測試用 java code
- resources 放測試用 Spring Boot 設定檔
- main 放我們要寫的code
- src (source)
- 測試的 class 以 原 class 的名字加上 Test 作為結尾 來命名
- 測試的 class 的 package 跟原 class 的 package 保持一致
都會放在com.example.demo 底下

真的需要單元測試嗎?
- 單元測試的數量不是越多越好
- 單元測試也是程式 ,程式越多就表示維護成本越高
- 單元測試的重要程度 = 影響使用者的程度 使用頻率越高的功能越需要單元測試
- 要加多少單元測試?
- 金融業: 能測多細就多細 ,錢很重要
- 軟體業:
- 使用 MockMvc 測式各個API 功能是否運作正常
- 重要的 Service 層可以加一些專屬的單元測試
- Dao 層比較少測 ,但如果有複雜的 sql 語法 , 可以額外添加測試
如何寫出好的單元測試
- 在寫單元測試時 ,要從使用者的角度去思考
- 經驗: 不要在時做完就直接寫單元測試 ,可以休息一下再寫
一定要記得測試 Error Case(錯誤驗證)- ex: 在測試getById 方法時 ,可以測試當 id 不存在時該怎麼處理? 當id 長度超過限制時該如何處理? Error Handling!!!
- 善用
IntelliJ Run Test With Converage,查看單元測試覆蓋的範圍
可以列出單元測試測出來的到底是哪幾行的程式 ,計算出單元測試的覆蓋率
More RunDebug >Run Tests in ‘’ with Converage
- 不要為了單純提升測試覆蓋率而寫單元測試 , 而是要思考是否有哪些場景沒考慮到
- 不要倍數字迷惑 ,並不是一定要 100% 覆蓋率才是完美 ,只要確保重要的功能有被測試到即可
- 如果測試中使用的@SpyBean 過多 ,表示功能切分的不夠好
- 盡量從功能面去區分 Service ,ex: PrdouctService ,OrderService ,UserService
- 和外部服務有關的API call ,獨立成一個 Service
- ex: 和 YouTube 有關的 API call 就統一放在 YouTubeService 裡面 在這個 Service 專門去處理和 YouTube 服務之間的 http 溝通
- 靠經驗多累積
測試驅動開發 TDD
全稱 Test-Driven Development 簡稱TDD
- 貫徹
先寫測試 ,再寫開發的精神 - 大致上可以分為五個步驟
- 選擇一個功能 ,先寫單元測試
- 單元測試失敗 (紅燈)
- 實作程式
- 單元測試成功 (綠燈)
- 持續重構程式